본문 바로가기
  • think normal
새로워지기/서른의 생활코딩

[생활코딩 따라가기] REACT, 대망의 CRUD~ 중, create

by 청춘만화 2019. 5. 28.

https://www.youtube.com/watch?v=nwwJ2xU7E8w&list=PLuHgQVnccGMCRv6f8H9K5Xwsdyg4sFSdi&index=28

 

 

1. Create

1. CRUD별 state.mode 값을 변경하기 

1) 일단 CUD목록을 만들자 

import React, {Component} from 'react';
import './App.css';

import Subject from "./component/Subject"
import TOC from "./component/TOC"
import Content from "./component/Content"


class App extends Component{
  constructor(props){ 
    super(props); 
    this.state={
      mode :"read", 
      welcome : {title:'welcome', desc:'hello react'},

      selected_content_id : 1,

      subject:{title:'WEB', sub:'world wide web !'},
      content:[
        {id:1, title:"HTML", desc:"HTML is HyperText "},
        {id:2, title:"CSS", desc:"Css is for design "},
        {id:3, title:"JS", desc:"javascript is for intrective "}
      ]
    }
  }

  render(){
    console.log('APP render & this is : ' , this);
    var _title, _desc = null;
    if(this.state.mode === 'welcome'){
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
    }else if(this.state.mode === 'read'){
      var i =0;
      while(i<this.state.content.length){
        var data = this.state.content[i];
        if(data.id === this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++; 
      }
    }
    
    return (
      <div className="App">

        <Subject 
          title={this.state.subject.title} 
          sub={this.state.subject.sub}

          onChangePage={function(){
            this.setState({
              mode:'welcome'
            });
          }.bind(this)}
          >
        </Subject>

         <TOC data={this.state.content}
          onChangePage={function(id){
            this.setState({
              mode : 'read',
              selected_content_id : Number(id)
            })
          }.bind(this)}
         ></TOC>

          <ul>
           <li><a href="/create" >create</a></li>
           <li><a href="/update" >update</a></li>
           <li><input type="button" value="delete"></input></li>
         </ul>

         <Content title={_title} desc={_desc}></Content>
      </div>
    );
  }
}
export default App;

2) CUD 목록을 컴포넌트로 변경

(1) Control.js

import React, {Component} from 'react';

class Control extends Component{
    render(){
      console.log('control render');
      return(
        <ul>
          <li><a href="/create" >create</a></li>
          <li><a href="/update" >update</a></li>
          <li><input type="button" value="delete"></input></li>
        </ul>
      );
    }
  }

  export default Control;

(2) app.js

 - 맨위에 

import Control from "./component/Control"

 - <ul>...</ul> 있던 자리에 아래 코드 추가

<Control></Control>

control render가 추가되었다.

 

3) 클릭할 때마다 모드변경 

앞서 실습한 TOC 또는 WRB 클릭 시 mode를 변경했던 방법과 동일하게 진해하면 되는거 같다 

* 깜박해서 삽질한 기억 : 양쪽 모두 .bind(this) 해줘야 한다는거~ ㅋ

app.js  - 의 <Control> </Control> 부분에 사용자정의 이벤트 설정하고 

<Control onChangeMode={function(_mode){
  this.setState({
  	mode:_mode
  })
}.bind(this)}></Control>

control.js - 여기서 앞에 설정한 이벤트 가져가 쓰고 

import React, {Component} from 'react';

class Control extends Component{
    render(){
      console.log('control render');
      return(
        <ul>
          <li><a href="/create" onClick={function(e){
            e.preventDefault();
            this.props.onChangeMode("create");
          }.bind(this)}>create</a></li>
          <li><a href="/update" onClick={function(e){
            e.preventDefault();
            this.props.onChangeMode("update");
          }.bind(this)}>update</a></li>
          <li><input type="button" onClick={function(e){
            e.preventDefault();
            this.props.onChangeMode("delete");
          }.bind(this)} value="delete"></input></li>
        </ul>
      );
    }
  }

  export default Control;

컨트롤 요소를 클릭할 때마다 mode 값이 바뀐다.

4) 새로운 컴포넌트 생성 및 조정

(1) 기존의 <Content> 영역이, mode가 read일 때와 create 일때를 구분하여 출력되도록 코드 조정

 <Content> </Content> 자리를 

{_content}로 바꾸고 

-  render(){ ...여기... return(); }   

//'여기'에, {_content}에 대한 조건문(만약 모드가 create 라면~) 추가

 (앞략)
 render(){
    console.log('APP render & this is : ' , this);
    var _title, _desc,_content = null;
    if(this.state.mode === 'welcome'){
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
      _content = <Read_Content title={_title} desc={_desc}></Read_Content>
    }else if(this.state.mode === 'read'){
      var i =0;
      while(i<this.state.content.length){
        var data = this.state.content[i];
        if(data.id === this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++; 
      }
      _content = <Read_Content title={_title} desc={_desc}></Read_Content>
    }else if(this.state.mode === 'create'){
      _content = <Create_Content></Create_Content>
    }
    
    return ( ... 중략 ...);
 }
 (말략 ㅋ)

- Create_Content.js - '폼 태그' 추가, 'submit 클릭시 얼럿 테스트'까지 한.

참고로 onSubmit는 순수 html 스펙, 그 안에{function(){}} 내용은 리액트 스펙
import React, {Component} from 'react';

class Create_Content extends Component{
    render(){
      console.log('Create render');
      return(
        <article>
          <h2>Create</h2>

          <form action="/create_process" method="post" 
            onSubmit={function(e){
              e.preventDefault();
              alert("submit");
            }.bind(this)}
          >
            <p><input type="text" name="title" placeholder="title"></input></p>
            <p><textarea name="desc" placeholder="description"></textarea></p>
            <p><input type="submit"></input></p>
          </form>
        </article>
      );
    }
  }
  export default Create_Content;

e.preventDefault(); 했으니까, 얼럿창의 '확인' 버튼을 눌러고 페이지가 리로드되지 않고 얌전히 있으면 성공. 

(2) 이젠, submit 하면, create 된 내용을 TOC 목록에 추가 ~

e.targrt이 form 자체를 가르킨다 
- 얼럿 코드 아래 debugger; 를 작성하고 새로고침해서 e.targrt의 상세 속성을 확인해볼 수 있다. 

- 일단 값 던지기

app.js

앞서 만든<Create_Content></Create_Content> 컴포넌트 안에 사용자정의 이벤트 onSubmit={}을 추가해 값을 받을 준비를 한다.

 

_content = <Create_Content onSubmit={function(_title, _desc){
  console.log(_title, _desc)
}.bind(this)}></Create_Content>

Create_Content.js 

form 태그 안에 있는 값들을 사용자정의 이벤트 onSubmit(제목, 내용)의 인자로 담아 app.js로 전달한다.

//debugger;
this.props.onSubmit(e.target.title.value, e.target.desc.value);

- 이번엔 UI 목록에 추가 

app.js

(---초략)
//*** 여긴 constructor(props){ ...여기(바로뒤에);  this.state={..} }

//1) contents의 수를 담은 변수를 추가하기(ui와 상관없으니, state 밖에 선언)
this.count_contents_id=3;

(---중략)

//*** 여긴 <Create_Content onSubmit={function(){ ...여기~... }}> 
//1) contents 맨뒤에 넣기 위해 +1 
this.count_contents_id=this.count_contents_id+1;
 
//2) 추가하기 - 아직 리액트는 모른다. 
this.state.content.push({
	id:this.count_contents_id, title:_title, desc:_desc
});

//3) 이제 리액트도 안다.
this.setState({
	content: this.state.content
});

(---말략)

- 하지만, 다시.      app.js 

다른 방식의 create - push VS concat 
- state에 값을 변경하는 경우 원본을 변경하지 않고 새로운 데이터를 넣는 concat를 추천한다
- 추후 성능개선 이슈 등에 더 유리하다 고 한다. 
import React, {Component} from 'react';
import './App.css';

import Subject from "./component/Subject"
import TOC from "./component/TOC"
import Control from "./component/Control"
import Read_Content from "./component/Read_Content"
import Create_Content from "./component/Create_Content"


class App extends Component{
  constructor(props){ 
    super(props); 

    this.count_contents_id=3;

    this.state={
      mode :"create", 
      welcome : {title:'welcome', desc:'hello react'},

      selected_content_id : 1,

      subject:{title:'WEB', sub:'world wide web !'},
      content:[
        {id:1, title:"HTML", desc:"HTML is HyperText "},
        {id:2, title:"CSS", desc:"Css is for design "},
        {id:3, title:"JS", desc:"javascript is for intrective "}
      ]
    }
  }

  render(){
    console.log('APP render & this is : ' , this);
    var _title, _desc,_content = null;
    if(this.state.mode === 'welcome'){
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
      _content = <Read_Content title={_title} desc={_desc}></Read_Content>
    }else if(this.state.mode === 'read'){
      var i =0;
      while(i<this.state.content.length){
        var data = this.state.content[i];
        if(data.id === this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++; 
      }
      _content = <Read_Content title={_title} desc={_desc}></Read_Content>
    }else if(this.state.mode === 'create'){
      _content = <Create_Content onSubmit={function(_title, _desc){
        //1
        this.count_contents_id=this.count_contents_id+1;

        //2-1
        // this.state.content.push({
        //   id:this.count_contents_id, title:_title, desc:_desc
        // });
        // this.setState({
        //   content: this.state.content
        // });

        //2-2
        var _new_content = this.state.content.concat({
          id:this.count_contents_id, title:_title, desc:_desc
        });
        this.setState({
          content: _new_content
        });

      }.bind(this)}></Create_Content>
    }
    
    return (
      <div className="App">

        <Subject 
          title={this.state.subject.title} 
          sub={this.state.subject.sub}

          onChangePage={function(){
            this.setState({
              mode:'welcome'
            });
          }.bind(this)}
          >
        </Subject>

         <TOC data={this.state.content}
          onChangePage={function(id){
            this.setState({
              mode : 'read',
              selected_content_id : Number(id)
            })
          }.bind(this)}
         ></TOC>
        <Control onChangeMode={function(_mode){
          this.setState({
            mode:_mode
          })
        }.bind(this)}></Control>
        {_content}
      </div>
    );
  }
}
export default App;

결과는 위와 동일~ 

 

1+a. 

1) push VS concat 

 

    (1) 원본을 바로 수정하지 않고, 복제본을 만들어서 수정한다. 

    (2) push는 shouldComponentUpdate를 사용 할 수 없다.

 

2) shouldComponentUpdate(newPros, newState)

     (1) TOC가 화면에 표시되기 위해서는 this.state.content[]이 반영되는데 

         - content[]의 내용이 바뀌지 않았을 때는 content[]의 render()가 실행될 필요가 없지만 계속 실행되고 있다.

     (2) shouldComponentUpdate(){ return ...} 를 추가하면

         render()보다 먼저 실행된다.

         - return 이 true 이면 모든 render()를 실행하고, false이면 render()를 실행하지 않는다.

         shouldComponentUpdate는 새롭게 바뀐 값과 이전 값에 각각 접근할 수 있다.

         새롭게 바뀐 값과 이전 값에 맞춰 render()의 실행여부를 개발자가 조절할 수 있다.

TOC.js

import React, {Component} from 'react';  

class TOC extends Component{
    shouldComponentUpdate(newProps, newState){
      console.log(" ======> shouldComponentUpdate",
        newProps.data,
        this.props.data
      );
      if(this.props.data === newProps.data){
        return false;
      }
      return true;
    }

    render(){
      console.log(' => TOC render');
      var lists=[];
      var data = this.props.data;
      var i=0;
      while(i<data.length){
        lists.push(<li key={data[i].id}>
          <a href={"/content/"+data[i].id}
            data-skdjfnsdkfj = {data[i].id}

            onClick={function(id,e){
              e.preventDefault();
              this.props.onChangePage(id);
            }.bind(this, data[i].id)}
          > {data[i].title}
          </a> </li>);
        i = i+1;
      }
      return(
        <nav>
          <ul>
            {lists}
          </ul>
        </nav>
      );
    }
  }

  export default TOC;

 

2) immutable 불변성 

      (1) Array의 특징 응용

       불변성에 대한 부분만 고려된다면, shouldComponentUpdate() 없이 push로도 구현할 수 있다. 

배열에서는 숫자만 같을 뿐 같은 값은 아니다

//2-1 + immutable 불변성

var _new_content = Array.from(this.state.content);

_new_content.push({
	id:this.count_contents_id, title:_title, desc:_desc
});

this.setState({
	content: _new_content
});

shouldComponentUpdate와 같은 결과, create 할때만 TOC의 render()가 호출된다

      (2) 객체의 경우,

객체를 복제하는 경우 이렇게~ Object.assign({}, a);

            but, 혹시나 해서 테스트해봒는데... ㅋ 

이 방법은 안됩니다~ true로 나오네요.  Object.assign(a);

      (3) 이렇게 왔다갔다하기 애매한 경우 -> 라이브러리를 활용할 수도 있음!

              모든 명령어들이~ 다~ 원본에 대해 불변하게 되기 때문에 혼란을 줄여줄 수 있다. 

https://github.com/immutable-js/immutable-js

 

immutable-js/immutable-js

Immutable persistent data collections for Javascript which increase efficiency and simplicity. - immutable-js/immutable-js

github.com

 

 

2. Update

https://www.youtube.com/watch?v=YKdebEty6uQ&list=PLuHgQVnccGMCRv6f8H9K5Xwsdyg4sFSdi&index=36

(ing)

 

 

 

댓글