본문 바로가기
React

React(18) Update 구현

by 새발개발JA 2021. 1. 12.
반응형

 

Update는 Create + Read 기능이 더해져있다. 

 

최종 목표 

업데이트 기능 구현하기 - Create의 폼에 입력받은 기존 컨텐츠의 내용을 수정한다.

 

App.js

1. 렌더함수 return에 <UpdateContent>자리를 만든다.

    1-1. 추후에 이 자리를 대신하여 {this.getContent()} 함수가 들어간다.

만들고 보니 너무 복잡하다. 흠... 함수를 좀 나누어 정리해야지

2. getContent()라는 함수를 만들어 깔끔하게 CRUD자리를 치워놓자. 

 

3. render()함수의 내용 (if문이 있는 로직부분) 그대로 가져오기 + 리턴은 _article 값 넣어주기 (1-1로 돌아가시오)

 

4. else if문 (모드===update) 일 때 ver. 추가하기

-  _content 변수를 getReadContent()를 불러내는 소환문으로 선언해놓고

  <UpdateContent data=_content>로 getReadContent()함수의 data들을 소환한다. 즉, 이미 저장된 글목록(데이터 배열)을 나타낸다.

   그래야 수정을 하던가 말던가 하지... 자 그럼 getReadContent()를 만들러 가보자!  (5로 가시오)

 

- onSubmit이벤트를 통해 서밋버튼을 누르면 일어나는 일들을 적어보자 { 

     - 핸들러메소드로 받는 인자인 id는 새로등록된 글번호를, title, desc은 사용자로부터 입력된 데이터들을 의미한다. (준비물)

     - 저 재료들로 요리를 해보자. 일단 Array.from()으로 원본 배열 contents를 담는 복사본배열 _contents 을 만든다. (이름이 비슷하쥬)

     - while문으로 복사본배열을 돌려서 하나하나씩 나열하는데 ...! 조건이 있음. 기존글 id 랑 = 입력글 id가 같으면..(아랫줄로가시오)

     - 기존의 id, title, desc를 인자로 받은(사용자가 입력한) _id, _title, _desc로 교체하라.. (즉 덮어씌우라 이말이야) 

  }

- onSubmit 잘 실행됬겠지? 그렇다면 state를 변경할 차례 (reason why? 재탕해야하니까 + 결과화면이 좀 달라져야지) {

     - _content 는 새로입력된 걸로 교체좀 하자 ^^

     - 읽기모드로 좀 바꾸자 (그래야 수정완료하면 수정된 결과페이지가 짠하고 나오지)

  }

 

5. getReadContent()함수 만들기

- 모드가 read일 때, while문으로 반복하여 그간 저장한 데이터 배열을 나열하는 기능을 가진 함수다.

- getContent ()안의 read 모드는 this.getReadContent()을 호출하면 제곧내가 된다.

**전체코드보기(복사용 첨부 / 더보기클릭)

더보기

import React, { Component } from 'react';

import Subject from "./components/Subject.js";

import Main from "./components/Main.js";

import Control from "./components/Control.js";

import CreateContent from "./components/CreateContent.js";

import UpdateContent from "./components/UpdateContent.js";

import ReadContent from "./components/ReadContent.js";

import './App.css';

 

class App extends Component {

  constructor(props){

    super(props);

    this.max_content_id = 3;

    this.state = {   

      mode:'read'

      selected_content_id:1

      head:{title:'WEB'sub:'world wide web!'},

      welcome:{title:'Welcome'desc:'Hello, React!!'},

      contents:[

        {id:1title:'HTML'desc:'HTML is for information'},

        {id:2title:'CSS'desc:'CSS is for design'},

        {id:3title:'JavaScript'desc:'JavaScript is for interactive'}      

      ]

    }

  }

  getReadContent(){

    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(){

    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){

        

        this.max_content_id += 1;

        var _contents = Array.from(this.state.contents);

        _contents.push({id:this.max_content_idtitle:_titledesc:_desc});

        this.setState({

          contents:_contents,

          mode:'read',

          selected_content_id:this.max_content_id

        });

        console.log(_title_desc);

      }.bind(this)}></CreateContent>

    } else if(this.state.mode === 'update'){

      _content = this.getReadContent();

      _article = 

        <UpdateContent data={_content} onSubmit={

          function(_id_title_desc){

          var _contents = Array.from(this.state.contents);

          var i = 0;

          while(i < _contents.length){

            if(_contents[i].id === _id){

              _contents[i] = {id:_idtitle:_titledesc:_desc};

              break;

            }

            i = i+1;

          }

          this.setState({

            contents:_contents,

            mode:'read'

          });

          console.log(_title_desc);

        }.bind(this)}></UpdateContent>

    } 

    return _article;

  }

  render() {

    console.log('App render'); 

    return(

      <div className="App">

        <Subject 

          title={this.state.head.title} 

          sub={this.state.head.sub}

          onChangePage={function(){

            this.setState({mode:'welcome'});

          }.bind(this)}>

        </Subject>        

        <Main 

          onChangePage={function(id){

            this.setState({

              mode:'read',

              selected_content_id:Number(id)

            });

          }.bind(this)}

          data={this.state.contents}>

        </Main>

        <Control onChangeMode={function(_mode){

          this.setState({

            mode:_mode

          })

        }.bind(this)}></Control>

        {this.getContent()}

      </div>

    );

  }

}

export default App;


 

UpdateContent.js

1. 생성자 함수 안의 state에 사용할 재료들을 좀 선언해주자

 

2. <input>과 <textarea>에 기존에 사용자가 입력한 내용을 가져오기 

- <input value={this.state.title}>로 App.js의 data에서 가져온 state인 title을 넣는다.

- <input value={this.state.desc}>로 App.js의 data에서 가져온 state인 desc을 넣는다.

 

**어 근데 수정이 안되요?

- props 자체는 Read Only이기 때문에 state로 선언해서 setState로 변경가능하게 만들어 줘야 합니다^^

- 하지만 여전히 수정은 안됨. onChange를 사용하여 setState로 state값이 바뀌는 이벤트를 만들어요 (3번으로 가시오)

  입력창에 변화가 일어났을 때 이벤트가 발생하게 됩니다

 

3. 근데... 이런식으로 onChange를 하나하나 선언해주는건 너무 코드중복이 많다. 

onChange에 ={this.inputFormHandler} 이런식으로 핸들러메소드를 따로 빼서 만드는 소환술을 사용해보자 

4. onChange 핸들러메소드만 따로 빼서 inputFormHandler() 라고 이름붙여준다. {

   - 그리고 setState를 사용해서 값을 바꾸려 하는데.. 

   - this.setState({title:e.target.value}); → 이러면 타이틀값만 바뀜. 

   - 이럴 때는 어떻게 해야할까?

   - this.setState({[e.target.name]:e.target.value}); → state에 맞게 내용이 변경이 된다

}

 

** [e.target.name]:e.target.value 처럼 key를 [ ]로 감싸면 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key 값으로 사용됩니다.

    → 해당 input태그의 name을 가리킨다.  

 

5. onChange={this.inputFormHandler.bind(this)} bind() 얘도 매번 중복된다. 따로 빼주자

constructor에서 {

   this.inputFormHandler = this.inputFormHandler.bind(this);

}

이렇게 바꿔주면 

onChange={this.inputFormHandler} → 밑에 렌더함수에서 소환할 때 간단하게 줄여쓸 수 있음 

 

6. 업데이트 시, 폼안에 데이터를 전송할 식별자를 만들어준다.

<input type="hidden" name="id" value={this.state.id}

  → hidden은 개발자들에게만 보인다. 폼을 서밋하면 name으로 받은 id 값이 서버 쪽으로 넘어간다.

  → 예를들어서 회원가입시 사용자의 아이피를 받는 경우 히든필드에 넣어서 폼 전송시 함께 전송한다.

 

7. <form> 안에 onSubmit 이벤트 만들기

**전체코드보기(복사용 첨부 / 더보기클릭)

더보기

import React, { Component } from 'react';

class UpdateContent extends Component {

  constructor(props){

    super(props);

    this.state={

      id:this.props.data.id,

      title:this.props.data.title,

      desc:this.props.data.desc

    }

    this.inputFormHandler = this.inputFormHandler.bind(this);

  }

  inputFormHandler(e){

    this.setState({[e.target.name]:e.target.value});

  }

  render() {

    console.log('UpdateContent render');

    return(

      <article>

        <h2>Update</h2>

        <form action="/create_process" method="POST" 

              onSubmit={function(e){

                e.preventDefault(); 

                this.props.onSubmit(

                  this.state.id,

                  this.state.title,

                  this.state.desc,

                );                   

              }.bind(this)}>

          {/* <input type="hidden" name="id" value={this.state.id}></input> */}

          <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" value="submit" />

          </p>

        </form>

      </article>

    );

  } 

}

export default UpdateContent;


 

반응형

댓글