🔗 생활코딩 React

1. 베이스 캠프

  • props
    • read-only
    • 컴포넌트 안에서 변경 불가
    • 이벤트를 통해 변경 가능
  • state
    • 비동기식
    • setState()로 변경 가능

2. create 구현

1) 소개

  • CRUD(Create Read Update Delete)
  • 동적으로 요소를 추가하는 기능 구현

2) mode 변경 기능

  • Control.js 생성 후 App.js에 import
    // Control.js
    class Control extends Component {
      render(){
        return (
          <ul>    // 각 링크 클릭 시 onChangeMode 함수 호출
            <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 onClick={function(e){    // delete는 위험하니까 버튼으로 생성
              e.preventDefault();
              this.props.onChangeMode('delete');
            }.bind(this)} type="button" value="delete"></input></li>
          </ul>
        );
      }
    }
    // App.js
    // onChangeMode 함수의 파라미터로 전달된 _mode 값을 state의 mode에 셋
    <Control onChangeMode={function(_mode){
      this.setState({
        mode:_mode
      })
    }.bind(this)}>
    </Control>

3) mode 전환 기능

  • 기존 Content 컴포넌트를 ReadContent로 수정
  • CreateContent.js 파일 생성하고 App.js에 import
  • 기존 App.js의 <ReadContent>...</ReadContent> 부분을 가변적으로 만들기 위해 {_article}로 대체
// App.js
  render() {
    var _title, _desc, _article = null;    // _artlcle 변수 선언
    // mode가 welcome이나 read면 기존 ReadContent가 _article 자리에 들어감
    if(this.state.mode === 'welcome'){
      ...
      _article = <ReadContent title={_title} desc={_desc}></ReadContent>
    }else if(this.state.mode === 'read'){
      ...
      _article = <ReadContent title={_title} desc={_desc}></ReadContent>
    // mode가 create면 _article에 CreateContent가 들어감
    }else if(this.state.mode === 'create'){
      _article = <CreateContent title={_title} desc={_desc}></CreateContent>
    }
    return (
      <div className="App">
       ...
        <Control ...>
        </Control>
        {_article}
      </div>
    );
  }

4) form

  • CreateContent.js에 폼 추가
    <article>
    <h2>Create</h2>
    <form action="/create_process" method="post"
      onSubmit={function(e){
        e.preventDefault(); // 페이지 전환 방지
      }.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>

5) onSubmit 이벤트

// App.js
...
}else if(this.state.mode === 'create'){
  _article = <CreateContent onSubmit={function(_title, _desc){
        console.log(_title, _desc);    // 값 잘 들어오나 찍어보기
      }.bind(this)}></CreateContent>
}
// CreateConent.js
<form action="/create_process" method="post"
  onSubmit={function(e){
    e.preventDefault(); // 페이지 전환 방지
    this.props.onSubmit(  // form(e) - target -  name 값(title/desc) - value
      e.target.title.value,    
      e.target.desc.value
    );
  }.bind(this)}
  >

🤦‍♀️
오... 잘 쓰면 엄청 유용할 거 같고 효율적일 거 같은데 머리가 너무 복잡하다.
계속 정리하고 연습해봐야 언제 어떻게 써야 할지 감이 올 것 같다.

6) contents 변경

  • form에서 받은 데이터를 state의 contents에 추가
    // App.js
    constructor(props){
      super(props);
      this.max_content_id = 3;    // max_content_id 선언
      ...
    }
    ...
    }else if(this.state.mode === 'create'){
      _article = <CreateContent onSubmit={function(_title, _desc){
            this.max_content_id = this.max_content_id + 1;    // max_content_id 증가
            var _contents = this.state.contents.concat(    // concat 함수로 contents에 정보를 추가한 _contents 선언
              {id:this.max_content_id, title:_title, desc:_desc}
            );
            this.setState({
              contents:_contents    // state의 contents 변경
            });
      }.bind(this)}></CreateContent>
    }

7) shouldComponentUpdate

  • push
    : 원본이 바뀜

    var a = [1, 2]
    a.push(3);
    console.log(a); // [1, 2, 3]
  • concat
    : 원본은 바뀌지 않고, 원본이 수정된 복제본 생성

    var a = [1, 2]
    a.concat(3);
    console.log(a);     // [1, 2]

👉 push 대신 concat을 사용하면 원본이 남아있으므로 코드가 일관되고 덜 혼란스러움

  • shouldComponentUpdate
    • 부모 컴포넌트가 업데이트되면 자식 컴포넌트들은 자동으로 다시 로드(렌더)됨
    • shouldComponentUpdate 함수를 사용하면 자식 컴포넌트에 변경할 내용이 없다면 render 함수를 실행하지 않음
// TOC.js
class TOC extends Component {
  shouldComponentUpdate(newProps, newState){  // 새롭게 바뀐 값, 기존 값에 접근 가능
    console.log('===>TOC render shouldComponentUpdate', 
    newProps.data // 새로운 값
    ,this.props.data  // 기존 값
    ); // concat이 아니라 push를 사용하면 기존값 === 새로운 값
    if(this.props.data === newProps.data){
      return false;    // render 호출하지 않음
    }
    return true; // render 호출
  }
    render(){
      ...
    }
  }

8) immutable

  • 원본이 불변하는 특성 (예: concat)

  • Array.from()

    • 배열 복제
      var a = [1, 2];
      var b = Array.from(a);    // a로 배열 생성(복제)
      console.log(a, b, a===b);    // [1, 2] [1, 2] false

      👉 pushArray.from()을 이용해서 복제한 후에 사용

  • Object.assign()

    • 객체 복제
    var a = {name:'bono'};
    var b = Object.assign({}, a);    // 빈 객체에 a를 넣어서 새로운 객체 생성
    console.log(a, b, a===b);    // {name:'bono'} {name:'bono'} false

🙆‍♀️
shouldComponentUpdateimmutable은 성능에 문제가 생길 때 더 알아볼 것!