[TIL] React 초급: CRUD - Update 구현하기

minami·2021년 6월 3일
0

React

목록 보기
6/12

11. Update 구현

11-1. Update 기능 구현을 위한 준비

  1. CreateContent 컴포넌트 내용을 복사해서 UpdateContent 컴포넌트 파일 생성

  2. App.js에서 render()함수 내용이 길어져서 보기 힘들어졌으므로 컨텐츠의 id값을 통제하는 부분과 컨텐츠 내용을 가져오는 부분을 생성자(constructor()) 함수 안으로 분리해서 넣기

    • getReadContent()

      getReadContent() {
          // while을 이용한 id값 통제
          var i = 0;
          while(i < this.state.contents.length) {
            var data = this.state.contents[i]
            if(data.id === this.state.selected_content_id) {
              return data;
              break;
            }
            i = i + 1;
          }
        }
    • getContent()

      getContent() {
          // 컨텐츠 영역에 표시할 _article도 정의해준다.
          var _title, _desc, _article = null;
          if(this.state.mode === 'welcome') {
            _title = this.state.welcome.title;
            _desc = this.state.welcome.desc;
            _article = <ReadContent title={_title} desc={_desc}></ReadContent>
          } else if(this.state.mode === 'read') {
            var _content = this.getReadContent();
            _article = <ReadContent title={_content.title} desc={_content.desc}></ReadContent>
          } else if(this.state.mode === 'create') {
            _article = <CreateContent onSubmit={function(_title, _desc) {
              // add content to this.state.contents
              this.max_content_id = this.max_content_id + 1;;
              // push()를 사용한 원본 배열 변경은 권장하지 않음.
              // this.state.contents.push(
              //   { id: this.max_content_id, title: _title, desc: _desc });
              // var _contents = this.state.contents.concat(
              //   { id: this.max_content_id, title: _title, desc: _desc }
              // )
              var newContents = Array.from(this.state.contents)
              newContents.push({id:this.max_content_id, title:_title, desc:_desc})
              this.setState({
                // contents: _contents
                contents: newContents
              })
              console.log(_title, _desc);
            }.bind(this)}></CreateContent>
          } else if(this.state.mode === 'update') {
            _content = this.getReadContent();
            _article = <UpdateContent data={_content} onSubmit={function(_title, _desc) {
              // add content to this.state.contents
              this.max_content_id = this.max_content_id + 1;;
              // push()를 사용한 원본 배열 변경은 권장하지 않음.
              // this.state.contents.push(
              //   { id: this.max_content_id, title: _title, desc: _desc });
              // var _contents = this.state.contents.concat(
              //   { id: this.max_content_id, title: _title, desc: _desc }
              // )
              var newContents = Array.from(this.state.contents)
              newContents.push({id:this.max_content_id, title:_title, desc:_desc})
              this.setState({
                // contents: _contents
                contents: newContents
              })
              console.log(_title, _desc);
            }.bind(this)}></UpdateContent>
          }
          return _article;
  3. render()함수 안의 컨텐츠 호출 부분 수정하기

    {/* 컨텐츠 영역에 표시할 내용을 변수로 지정 */}
    {this.getContent()}

11-2. Update Form 구현하기

  • 수정할 input value값 가져오기

    input value값을 props로 가져오면 경고 및 값 변경이 불가능한 오류 발생

    <p>
        <input type="text" name="title" placeholder="title" value={this.props.data.title}></input>
    </p>

    👉 props값은 Read-only이므로 onChange 핸들러를 같이 사용하지 않으면 값을 변경할 수 없다는 경고가 뜬다. 따라서 props값을 변경할 수 있는 state값으로 가져와서 변경해야 한다.

    input value값은 state값으로 가져오고 onChange핸들러를 추가해 준다.

    // value값에 바로 this.props.data.title을 넣으면 props는 read-only값이라 값을 변경하지 못하므로 생성자로 props를 state로 받아서 value를 state값으로써 바꿀 수 있게 해준다.
        constructor(props) {
            super(props);
            this.state = {
                title: this.props.data.title,
                desc: this.props.data.desc
            }
        }
        inputFormHandler(e) {
            this.setState({title: e.target.value});
        }
    <p>
        <input type="text" name="title" placeholder="title" value={this.state.title} onChange={function(e) {
                            this.setState({title: e.target.value});
            }.bind(this)}></input>
    </p>
  • 수정할 textarea의 내용 state로 가져오기

    textarea value로 가져오지 않으면 경고 발생

    <p>
        <textarea name="desc" placeholder="description">{this.state.desc}</textarea>
    </p>

    👉 defaultValue 또는 value값을 설정해줘야 한다는 경고가 뜬다. input value를 설정해준 것처럼 textarea 태그 안에 valuestate값을 가져오고 onChange핸들러를 설정해줘야 한다.

    textarea value값을 state값으로 가져오고 onChange핸들러를 추가해 준다.

    <p>
        <textarea name="desc" placeholder="description" value={this.state.desc} onChange={function(e) {
                            this.setState({desc: e.target.value});
                        }.bind(this)}></textarea>
    </p>
  • 공통으로 사용되는 bind(this)를 따로 빼주고, titledesc 각각에 따라 onChange핸들러가 동작하도록 변경하기

    import { Component } from 'react';
    
    class UpdateContent extends Component {
        // value값에 바로 this.props.data.title을 넣으면 props는 read-only값이라 값을 변경하지 못하므로 생성자로 props를 state로 받아서 value를 state값으로써 바꿀 수 있게 해준다.
        constructor(props) {
            super(props);
            this.state = {
                title: this.props.data.title,
                desc: this.props.data.desc
            }
            // 공통으로 사용되는 bind(this)를 넣은 값을 변수로 빼준다.
            this.inputFormHandler = this.inputFormHandler.bind(this);
        }
        inputFormHandler(e) {
            // [e.target.name]으로 title과 desc값을 각각 변경할 수 있다.
            this.setState({[e.target.name]: e.target.value});
        }
        render() {
            console.log(this.props.data);
            console.log('UpdateContent render')
          return (
            <article>
                <h2>Update</h2>
                <form action="/update_process" method="post" 
                onSubmit={function(e) {
                    e.preventDefault();
                    this.props.onSubmit(
                        e.target.title.value,
                        e.target.desc.value
                    );
                }.bind(this)}
                >
                    <p>
                        <input type="text" name="title" placeholder="title" value={this.state.title} onChange={this.inputFormHandler}></input>
                    </p>
                    <p>
                        <textarea name="desc" placeholder="description" value={this.state.desc} onChange={this.inputFormHandler}></textarea>
                    </p>
                    <p>
                        <input type="submit"></input>
                    </p>
                </form>
            </article>
          );
        }
      }
    
      export default UpdateContent;

11-3. Update 구현 마무리 - state 변경

  • 컨텐츠의 id값을 가져오는 코드를 UpdateContent 컴포넌트에 추가하기

    return (
        <article>
            <h2>Update</h2>
            <form action="/update_process" method="post" 
                onSubmit={function(e) {
                    e.preventDefault();
                    this.props.onSubmit(
                        this.state.id,
                        this.state.title,
                        this.state.desc
                    );
                }.bind(this)}
                >
                {/* id값을 가져오는 코드 추가 */}
                <input type="hidden" name="id" value={this.state.id}></input>
  • App.js에서 컨텐츠의 id값을 기준으로 해당 id값을 가진 컨텐츠 내용을 수정하여 배열에 반영하도록 하기

    else if(this.state.mode === 'update') {
          _content = this.getReadContent();
          _article = <UpdateContent data={_content} onSubmit={function(_id, _title, _desc) {
            // push()를 사용한 원본 배열 변경은 권장하지 않음.
            // this.state.contents.push(
            //   { id: this.max_content_id, title: _title, desc: _desc });
            // var _contents = this.state.contents.concat(
            //   { id: this.max_content_id, title: _title, desc: _desc }
            // )
            // 업데이트할 컨텐츠의 id값을 이용해서 해당 id를 가진 컨텐츠를 배열에서 업데이트
            var _contents = Array.from(this.state.contents);
            var i = 0;
            while(i < _contents.length) {
              if(_contents[i].id === _id) {
                _contents[i] = {id: _id, title: _title, desc: _desc};
                break;
              }
              i = i + 1;
            }
            this.setState({
              contents: _contents
            })
          }.bind(this)}></UpdateContent>
        }
  • App.js에서 update 기능 동작 후에 모드를 read로 바로 변경해주는 코드 추가

    this.setState({
        contents: _contents,
        mode: 'read'
    });
  • App.js에서 create 기능 동작 후에 모드를 read로 바로 변경해주는 코드와 컨텐츠 배열의 맨 마지막 id값을 변경해주는 코드 추가

    this.setState({
        contents: _contents,
        mode: 'read',
        selected_content_id: this.max_content_id
    });
profile
함께 나아가는 개발자💪

0개의 댓글