내가 한 노력들

[ React ] CRUD - Create 구현 본문

카테고리 없음

[ React ] CRUD - Create 구현

JONGI-N CHOI 2022. 1. 15. 12:00

앞선 과정에서 이미 Read기능을 실현했기 때문에, 이번에는 Create기능을 구현할려고 합니다. 

CRUD기능을 구현하기 위해서 우선, 해당 버튼을 클릭했을 때, create, update, delete 기능이 가능하도록 구현할려고 합니다. 


Control 컴포넌트 생성

App.js

this.state = { 
  mode: "Read",
  selected_content_id: 0,
  header: {title: 'WEB', subject: 'WORLD WIDE WEB'},
  welcome: {title: 'Welcome', subject: 'Hello, React'},
  contents: [
    {id: 1, title: "HTML", desc: "HTML IS ..."},
    {id: 2, title: "CSS", desc: "CSS IS ..."},
    {id: 3, title: "JAVASCRIPT", desc: "JAVASCRIPT IS ..."}
  ]
};

우선,  state에 mode 라는 새로운 변수를 추가합니다. 

 

Control.js

import React from 'react';

class Control extends React.Component {
  constructor(props) {
    super(props);
    this.onChangeMode = this.onChangeMode.bind(this);
  }
  onChangeMode(e) {
    e.preventDefault();
    this.props.onChangeMode(e.target.outerText);
  }

  render() {
    return (
      <ul>
        <li><a href="!#" onClick={this.onChangeMode}>create</a></li>
        <li><a href="!#" onClick={this.onChangeMode}>update</a></li>
        <li><button onClick={this.onChangeMode} type="submit">delete</button></li>
      </ul>
    );
  }
}

export default Control;

CRUD를 컨트롤하기 위한 버튼 컴포넌트를 생성합니다. 

onChangeMode(e) {
    e.preventDefault();
    this.props.onChangeMode(e.target.outerText);
  }

control에서는 onChangeMode 라는 함수를 하나 선언했습니다. 

함수가 실행되었을 경우, 상위 컴포넌트에서 받은 onChangeMode 함수에 e.target.outerText를 인수로 실행하는 것입니다. 

 

여기서 우선 e.target.outerText란 event 함수에는 여러 정보가 담겨있는데 그중에서 target.outerText는 이벤트가 발생한 엘리먼트의 Text값을 가져오는 것 입니다. 


onChangeMode 함수 정의

 

 

이번엔 App.js에 돌아가서 onChangeMode 함수를 정의해줄 차례입니다. 

App.js

onChangeMode(_mode) {
    this.setState({
        mode: _mode
    });  
  }

위의 함수를 추가합니다. 그러면 control 컴포넌트에서 보낸 mode 값으로 setState로 mode값을 변경합니다. 

render() {    
    ...생략

    let _article = null;
    let _mode = this.state.mode;

    if (_mode === 'read') {
      _article = <ReadContent title={_title} desc={_desc}/>
    } else if (_mode === 'create') {
      _article = <CreateContent />
    }
    
    return (
      <div>
        <Header title={this.state.header.title} subject={this.state.header.subject}/>
        <TOC 
          content={this.state.contents} 
          onChangePage = {this.onChangePage} 
        />
        <Control onChangeMode={this.onChangeMode} />
        {_article}
      </div>
    );
  }

그리고, 기존의 App.js를 살짝 변경했습니다. 

mode에 따라서, 본문의 컴포넌트를 변경하기 위함입니다. 

mode가 read일 경우에는 기존처럼 리스트를 클릭할 때마다, 해당 내용의 본문내용을 볼 수 있도록 

ReadContent 컴포넌트를, mode가 create일 경우에는 CreateContent 컴포넌트를 보이도록 변경했습니다. 


CreateContent 컴포넌트 생성

function CreateContent(props) {
  return (
    <article>
      <h1>Create</h1>
      <form onSubmit={function(e) {
          e.preventDefault();
          props.onSubmit(
              e.target.title.value,
              e.target.desc.value
          );
      }}>
          <p><input type="text" name="title" placeholder="title"/></p>
          <p><textarea name="desc" placeholder="description"></textarea></p>
          <input type="submit" value="제출" />
      </form>
    </article>
  );
}

export default CreateContent;

 

<form onSubmit={function(e) {
  e.preventDefault();
  props.onSubmit(
      e.target.title.value,
      e.target.desc.value
  );
}}>

onSubmit도 onClick과 마찬가지로 React에서 사용되는 문법중 하나입니다. 

submit버튼을 클릭했을 경우에 해당의 함수가 실행되는 것입니다. 

 

submit되었을 경우 상위 컴포넌트에서 전달받은 onSubmit 함수를 실행시킵니다. 


saveContent 함수 선언

그러면, 다시 App.js에 onSubmit 함수를 선언하겠습니다. 

 

App.js

saveContent(_title, _desc) {
    let max_content_id = this.state.contents.length + 1
    let _contents = this.state.contents.concat(
      {id: max_content_id, title: _title, desc: _desc}
    )
    this.setState({
      contents: _contents
    })
  }

CreateContent 컴포넌트에서 submit을 통해 전달한, title과 desc값을 가지고 기존 state의 contents값에 추가를 해줘야하는데, 여기서 주의할점이 있습니다. 

 

이번 Create 구현에서 가장 중요한점이 될 수 있는 부분입니다. 

그건, 데이터를 추가할 때 concat을 사용하고 있다는 점입니다. 

보통 Array에 새로운 데이터를 추가할 때 사용하는 것은 push()입니다. 그런데 여기서 concat()을 사용한 이유가 있습니다. 

 

그것은 push는 기존 array를 직접 바꾸지만 , concat은 기존 array에는 영향을 미치지 않는다는 점입니다. 

 

이부분이 왜 중요한지는, 앱을 최적화하기 위해서 shouldComponentUpdate()라는 함수를 사용하게 되는데 

여기서 기존의 props값과 새롭게 변경된 props값과 비교를 해서 변경이 있을 경우에만 render 함수를 실행시키는 작업을 할 수 있습니다. 

 

기존에는 props나 state에 변경이 있으면, 해당 컴포넌트에 영향이 없음에도 불구하고, 모든 render가 실행이 됩니다. 

이러면, 프로젝트의 규모가 클 경우에는 엄청나게 자원을 낭비하게 될 가능성이 있습니다.

그렇기 때문에 변경이 있는 컴포넌트만 render를 실행시키는 작업입니다. 

 

그런데, push를 사용하면 원본의 데이터가 변형되기 때문에 기존의 props값과 새로운 props값이 동일하게 됩니다. 

그러면, 변경이 있음에도 불구하고 react는 변경되었는지 모르고 해당 render를 무시하게 됩니다.

 

따라서, 변경이 되었음에도 불구하고 브라우저에는 적용이되지 않습니다. 

 

위와같은 문제점이 있기 때문에 push를 사용하지 않고, concat을 사용하여 원본 데이터에는 영향을 주지 않는 방향으로 개발을 하는 것 입니다. 

 

이번에는 concat을 사용했지만, 꼭 concat을 사용할 필요는 없습니다. 

Array.from(array 타입) 을 사용하면, array를 복제하게 되는데, 복제를 한뒤에 push해도 됩니다. 

복제하기 때문에 기존의 array는 전혀 영향을 주지 않습니다 .

이런 것을 immutable이라고 합니다. 

 

 

 

그럼, 브라우저에서새롭게 React라는 타이틀을 새롭게 추가합니다. 

 

 

 

 

 

 

그럼 리스트에 새롭게 React가 추가된 것을 확인할 수 있습니다. 

 

 

 

 

 

 

 

 

 

 

 


실제로 직접 개발하면서, 블로그를 작성하느라 이곳저곳 코드가 변경되 보기 힘든 부분이 있을 수 있습니다.. 

 

이번 Create 과정에서 중요한점은 기존 state값을 변경하기 보다는 immutable타입을 사용하여 값을 변경하는 점을 기억해두면 좋을 것 같습니다.