본문 바로가기
JAVASCRIPT/React

[생활코딩 React 강의 4] CRUD 중 Create 구현하기

by sjs_2215 2019. 7. 1.

생활 코딩 리액트 강의 <https://www.youtube.com/playlist?list=PLuHgQVnccGMCRv6f8H9K5Xwsdyg4sFSdi

지금까지 우리는 CRUD(Create, Read, Update, Delete) 중 Read까지했음

이 장부터 create 구현

19.1부터 create 구현:소개



하려고 하는 것


  1. toc와 content 사이에 새로운 컴포넌트를 만들어 생성/수정/삭제 버튼을 구현
  2. 생성 버튼 클릭 시: App 컴포넌트에 mode가 read->create로 바뀔 것

그에 따라 Content, 읽기에서 사용되는 컴포넌트가, 글을 추가할 때 사용되는 컴포넌트로 바뀔 것.

  • 이 컴포넌트에는 form이 들어가 있을 것.
  • form에 정보를 입력, submit 버튼 클릭 시
  1. App 컴포넌트에 contents 목록에 새로운 컴포넌트 정보가 id,제목,본문이 객체로 담겨 contents에 추가될 것임
  2. 새로 추가한 컴포넌트를 클릭하면 mode가 다시 create->read로 바뀌고, selected_content_id가 해당 id로 바뀌고, 본문에 ( TOC에) 해당 내용이보여질 것임



1-1. TOC와 CONTENT 사이에 CREATE,UPDATE,DELETE mode로 진입할 수 있는 버튼 만들기


  • create,update,delet에 href 태그와 button 추가하기
<ul>
        <li> <a href="/create">create</a></li>
        <li> <a href="/update">update</a></li>
        {/*delete는 링크를 사용하지 않고(페이지 개념이 아닌) 버튼(오퍼레이션 개념)을 사용
          이유: 빠른 동작을 위해 해당 페이지를 미리 방문을 해두는 소프트웨어가 구현되어 있다고 치면,
          delete도 링크로 구현되어 있으면 delete도 미리 방문해서 삭제해버릴수도 있기 때문*/}
        <li> <input type="button" value="delete"></input></li>
      </ul>

  • App.js에 있던 위 코드를 Control이라는 새로운 컴포넌트를 만들어 밖으로 빼는 작업 진행

Control.js

import React, {Component} from 'react';

class Control extends Component {
  render() {
    console.log('subject render'); //render 호출되는지 로그 찍어보기
    return  (
      <ul>
        <li> <a href="/create">create</a></li>
        <li> <a href="/update">update</a></li>
        {/*delete는 링크를 사용하지 않고(페이지 개념이 아닌) 버튼(오퍼레이션 개념)을 사용
          이유: 빠른 동작을 위해 해당 페이지를 미리 방문을 해두는 소프트웨어가 구현되어 있다고 치면,
          delete도 링크로 구현되어 있으면 delete도 미리 방문해서 삭제해버릴수도 있기 때문*/}
        <li> <input type="button" value="delete"></input></li>
      </ul>
    );
  }
}

export default Control;

App.js

{/*생략*/}
import Control from "./components/Control";
{/*생략*/}
<Control></Control>//해당 위치에
{/*생략*/}



2-1. Control 컴포넌트에서 3개 중 하나를 클릭 시 mode가 바뀌게 만들기


  • Control 컴포넌트에 onChangeMode라는 이벤트를 정의하여 이벤트 핸들러를 설치

(=이벤트가 실행되어야 하는 함수를 핸들러라고 부름)

<Control
      onChangeMode={function(){

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

  • 이 핸들러를 설치한 후, create/update/button을 클릭했을 때 onChangeMode핸들러가 실행되게 할 것임
        <a href="/create"
        onClick={function(e) {
          this.props.onChangeMode('');
        }>

         <a href="/update"
        onClick={function(e) {
          this.props.onChangeMode('');
        }>

        <input
        onClick={function(e) {
          this.props.onChangeMode('');
        }> 

  • 그리고 해당 버튼 클릭할때마다 onChangeMode에게 나는 create야~ 나는 update야~를 알려 주는 것
          this.props.onChangeMode('create');

          this.props.onChangeMode('update');

          this.props.onChangeMode('delete');

  • 이렇게 알려주면 (=onChangeMode가 호출될때) 알려주는 것을 받는 _mode라는 첫번째 인자를 만들고
onChangeMode={function(_mode){ 

  • 받은 인자의 mode로 바꿔 주면 됨
        this.setState({
          mode:_mode,
        })

  • 풀 코드

App.js 중 바뀐 부분

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

Control.js 중 바뀐 부분

<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) {
       e.preventDefault();
       this.props.onChangeMode('delete');
     }.bind(this)} type="button" value="delete"></input></li>
   </ul>



2-2. mode에 따라 Content에 적절하게 내용이 변경되게 하기


  • Content.js 파일 한개로 이루어졌던 것을 ReadContent로 이름 변경, CreateContent는 새로 생성해 바꾸기

CreateContent.js

import React, {Component} from 'react';

class CreateContent extends Component {
  render() {
    console.log('Content render'); //render 호출되는지 로그 찍어보기
    return(
      <article>
        <h2>Create</h2>
        <form>

        </form>
        </article>
    );
  }
}

export default CreateContent;

  • ReadContent가 표시될 자리에 하나의 변수를 두어 가변적으로 움직일 수 있게 변경

변경 전 App.js 일부 코드

<ReadContent title={_title} desc={_desc}></ReadContent>

변수로 변경 후 App.js 일부 코드

var _article = null;

{/*원래 코드가 있던 위치에*/}  {_article}

  • mode가 welcome이거나 read일 때는 default로 mode가 ReadContent이게 설정 해주기
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>
    }

  • if-else if 문에 read뿐만 아니라 mode가 create일 때 조건 도 만들어주기
else if(this.state.mode === 'create'){
      _article = <CreateContent></CreateContent>
    }



2-3. CreateContent의 form 영역 구현


  • Title 적는 박스, Description 적는 박스, submit 버튼 UI 구현

CreateContent.js 일부

여기서 placeholder는:

form에 아무것도 입력하지 않았을 때 디폴트로 보여지는 텍스트를 설정할 때 사용

<form>
         <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>

  • form 태그 자체를 정의하기

    1. 데이터를 어디다 전송할지 action값을 줌

      action="/create_process"

      create_process라는 페이지로 사용자가 입력한 정보를 전송할 것이다를 뜻함

    2. method="post"로 정해 url에 노출안되게 넘기기

    3. onSubmit이라는 이벤트를 호출

      submit 버튼을 포함한 전체 form 태그에 onSubmit이라는 이벤트를 설치해두면, 그 이벤트가 실행되도록 약속을 하는 것과 마찬가지 (->html form 태그의 고유 기능)

    4. e.preventDefault();는 앞 강의에서도 말했다싶이 화면전환을 방지하기 위함임.

      이 문장이 없다면 submit 버튼 클릭시 form태그의 action이 가리키고 있는 페이지로 화면이 이동될 것임

CreateContent.js 일부

<form action="/create_process" method="post"
        onSubmit={function(e){
          e.preventDefault();
          alert('submit complete');
        }.bind(this)}>



3-4. 입력된 데이터를 CreateContent를 가져다 쓰고 있는 App 컴포넌트의 contents라는 데이터 끝에다 추가하기


  1. Submit 버튼 클릭 시 App.js CreateContent의 이벤트로 설치된 함수를 실행 시키려고 함. && 이 함수의 인자로 title과 desc를 전달받을 것임
else if(this.state.mode === 'create'){
      _article = <CreateContent onSubmit={function(_title,_desc){
        //add content to this.state.contents

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


  1. CreateContent.js에선 App.js CreateContent의 onSubmit이라는 props를 호출 할 것임
<form action="/create_process" method="post"
        onSubmit={function(e){
          e.preventDefault();
          debugger;
          this.props.onSubmit(첫번째인자(제목),두번째인자(본문내용));
          alert('submit complete');
        }.bind(this)}>


  1. 그렇담,, App.js에 넘겨줄 제목과 본문내용 데이터를 어떻게 표현-할 것인가?

-> debugger; 이용! (아래 사진 참고)

이를 통해 title과 description은 내부적으로

e.target.title.value

e.target.desc.value라는 것을 알 수 있음

이를 그대로 props의 인자로 넘겨주면 됨

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

  1. 마지막으로, 얻어온 데이터를 contents 데이터 끝에다 추가해주면 됨

-지금까지의 contents id가 몇번인지 알아내기

this.max_content_id=3;

state값으로 하지 않고 객체의 값으로 함.

max_content_id는 단순히 id값을 알아낼때 사용하는 것일뿐 ui와 상관없어서 불필요한 렌더링을 피하기 위해 씀


-알아낸 id번호에 +1을 하고, title과 desc를 추가해줌

this.max_content_id=this.max_content_id+1;
this.state.contents.push(
    {id:this.max_content_id,title:_title,desc:_desc}
);

하지만 위 코드 틀림


-> react에게 state가 변경되었다고 알리기 위해 setState를 써줘야 함

this.max_content_id=this.max_content_id+1;
this.state.contents.push(
    {id:this.max_content_id,title:_title,desc:_desc}
);

{/*밑 부분 추가*/}
this.setState({
    contents:this.state.contents
});

-push대신 concat쓰게 변경


this.max_content_id=this.max_content_id+1;

var _contents = this.state.contents.concat(
          {id:this.max_content_id, title:_title, desc:_desc}
        )

//밑 부분 추가
this.setState({
    contents:_contents
});


Comments