본문 바로가기

Frontend/React

[React] Create기능 구현

728x90

생활코딩 : 리액트편을 보고 작성된 게시글 입니다.

 

React 만을 이용하여 READ/CREATE/UPDATE/DELETE 구현가능!

 

Read : 이전까지 계속 해오던 기능! 

Create / Update / Delete

 

목표

 

 

1단계 버튼 컴포넌트 만들기

링크와 버튼으로 버튼 제작

App.js 

render()함수 내 버튼을 만들기를 원하는 부분에 추가 

        <ul>
          <li><a href="/create">create</a></li>
          <li><a href="/update">update</a></li>
          <li><input type="button" value="delete"></input></li>
        </ul>

주의* : delete기능은 링크로 구현하지 않는 것이 좋음 

 

컴포넌트로 만들어주기 

컴포넌트 명 : <Control>

src/component/ 경로상에 Control.js파일을 만들어서 컴포넌트를 제작

Control.js

import React, { Component } from 'react';

class Control extends Component {
    render(){
      return(
        <ul>
        <li><a href="/create">create</a></li>
        <li><a href="/update">update</a></li>
        <li><input type="button" value="delete"></input></li>
      </ul>

      );
    }
  }


export default Control; //외부에서 사용을 허용

 

App.js에서 Control을 import하고, 컴포넌트로 대체해주기

import Control from './components/Control';



class App extends Component {

  constructor(props){ 
    super(props); 

    this.state ={
			//생략
      ]
    }

  }


render(){
  
  //생략
  
    return (
      <div className="App">

        //생략 <Subject></Subject><TOC></TOC>

        <Control></Control>

        //생략 <Content></Content>
        
      </div>
      );
  
}
}

export default App;

 

 

2단계 버튼을 누르면 mode변경

 

onClick 과 onChangeMode(사용자 정의함수) 를 이용해서 

하위 컴포넌트인 Control.js 에서 버튼이 눌릴때 상위 컴포넌트인 App.js의 State mode를 변경해줌

App.js

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

onChangeMode 함수를 만들어 매개변수로 전달된 _mode변수로 mode를 변경해줌

 

Control.js

import React, { Component } from 'react';

class Control extends Component {
    render(){
      return(
        <ul>
        <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>

      );
    }
  }


export default Control; //외부에서 사용을 허용

 

 

 

3단계 mode에 맞추어 Content를 변경

mode 에 맞추어 CreateContent / ReadContent가 다르게 보여져야 하므로 

기존의 Content 컴포넌트의 이름을 ReadContent로 변경하고 CreateContent를 새로 만들어줌

 

CreateContent.js

import React, { Component } from 'react';

class CreateContent extends Component{


    render(){
      return(
        <article>
          <h2>Create</h2>
            
        </article>
      );
    }
  }


  export default CreateContent; //외부에서 사용을 허용

 

 

버튼을 누를때 변경되는 mode에 맞추어 create mode의 경우 

Content가 표시되는 부분에 ReadContent대신 CreateContent 컴포넌트를 띄워주기

즉, Content부분은 이제 가변적으로 다른 컴포넌트가 띄워지므로 변수를 사용함 (_article 변수를 사용해서 상황에 따라 다른 컴포넌트를 담아줌)

if-else문을 이용해서 State.mode가 어떤 상태인지 확인하고, 그에 따라 <ReadContent> <CreateContent>를 적절하게 사용

 

 

App.js

import React, { Component } from 'react';
import './App.css';
import TOC from "./components/TOC";
import Subject from "./components/Subject"
import ReadContent from './components/ReadContent';
import Control from './components/Control';
import CreateContent from './components/CreateContent';



class App extends Component {

  constructor(props){ 
    super(props); 

    this.state ={
      mode : 'read',
      subject : {title:"WEB", sub:"world wide web!"},
      selected_content_id : 2,
      welcome : {title:"welcome", desc:"hello, react!"},
      contents : [
        {id:1, title:'HTML', desc:'HTML is for information'},
        {id:2, title:'CSS', desc:'CSS is for design'},
        {id:3, title:'JavaScript', desc:'JavaScript is for interactive'}
      ]
    }

  }


render(){
  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 i = 0;
    while(i<this.state.contents.length){
        var data = this.state.contents[i];
        if(data.id === this.state.selected_content_id){
          _title = data.title;
          _desc = data.desc;
          break;
        }
      i=i+1;
    }
    _article = <ReadContent title={_title} desc={_desc}></ReadContent> 
  }
  else if(this.state.mode ==='create')
  {
    _article = <CreateContent></CreateContent> 
  }
    return (
      <div className="App">

		//생략         

        {_article}

      </div>
      );
  
}
}

export default App;

welcome , read mode : Read Content

create mode : CreateContent

 

결과 

Create를 누르면 아까 작성해둔 CreateContent부분 <h2>Create</h2>가 출력됨을 확인

 

mode 부분도 변경됨을 확인 할 수 있음

 

 

 

4단계 CreateContent작성

 

입력을 받는 from작성 

import React, { Component } from 'react';

class CreateContent extends Component{


    render(){
      return(
        <article>
          <h2>Create</h2>
          <form action="/create_process" method="post">
                <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>
      );
    }
  }


  export default CreateContent; //외부에서 사용을 허용

다음과 같이 입력값을 넘겨줄 수 있는 form태그를 이용하여

title/ desc를 적는 텍스트공간과 submit버튼을 만들어준다. 그리고 post방식으로 넘겨줌

 

이때 , action을 통해 다른 page(create_process)로 넘기지 않고 바로 해당 페이지에서 해결해 주기 위해 onSubmit함수를 사용

onSubmit event

submit버튼을 포함하고 있는 from tag안에 onSubmit event를 설치하면, submit버튼을 눌렀을 때 해당 event가 실행됨

onSubmit event를 이용해 상위 컴포넌트인 App.js에 함수의 인자로 title과 desc값을 넘겨주는 방식으로 값을 전달

CreateContent.js

          <form action="/create_process" method="post" 
          onSubmit={function(e){
              e.preventDefault();
              this.props.onSubmit(title변수,desc변수); //<-인자로 title과 desc값을 넘겨주기 
          }.bind(this)}>

App.js

 else if(this.state.mode ==='create')
  {
    _article = <CreateContent onSubmit={function(_title,_desc){
      //add content to this.state.contents
      
    }.bind(this)}></CreateContent> 
  }

함수의 인자로 _title, _desc를 받아와 state내 content에 추가해주면됨

 

이제 실제로 CreateContent내에서 사용자 입력을 받은 title, desc를 어느 변수에 저장하는지 알아내면 완료

debugger(함수 내 디버그하고 싶은 곳에 작성 후)와 개발자도구 Source -> CreateContentjs->Scope내에서 찾아볼 수 있음 

title에 적힌 값은  e.tartget.title.value

desc에 적힌 값은 e.target.desc.value

* e.target은 해당 함수를 사용한 태그 전체를 가리킴 : 여기서는 form태그

 

즉, CreateContent.js에서 임시의 변수로 두었던 곳을 변경 가능 

CreateContent.js

          <form action="/create_process" method="post" 
          onSubmit={function(e){
              e.preventDefault();
              this.props.onSubmit(e.target.title.value,e.target.desc.value); //<-인자로 title과 desc값을 넘겨주기 
          }.bind(this)}>

 

 

 

5단계 Add content to this.state.contents

 

App.js

 else if(this.state.mode ==='create')
  {
    _article = <CreateContent onSubmit={function(_title,_desc){
      //add content to this.state.contents
      
    }.bind(this)}></CreateContent> 
  }

이제 _title, _desc로 넘겨받은 데이터를 기반으로 

 

State부분에 데이터를 추가해봅시다. 

  constructor(props){ 
    super(props); 
    this.max_content_id=3;
    this.state ={
      mode : 'read',
      subject : {title:"WEB", sub:"world wide web!"},
      selected_content_id : 2,
      welcome : {title:"welcome", desc:"hello, react!"},
      contents : [
        {id:1, title:'HTML', desc:'HTML is for information'},
        {id:2, title:'CSS', desc:'CSS is for design'},
        {id:3, title:'JavaScript', desc:'JavaScript is for interactive'}
        //여기에 데이터 추가
      ]
    }

  }

 

새로운 id값 부여하기 

이미 있는 content의 max id값보다 1큰 수를 자동으로 지정해주어야함

max_id 값을 저장하는 변수 생성 

  constructor(props){ 
    super(props); 
    this.max_content_id=3; //현재 최대 id값을 초기값으로 지정
    this.state ={
		//생략
    }

  }

state를 표현하는게 아니므로 state내부에 만들지 않는 것이 좋음 

 

Contents는 배열 데이터 -> 배열에 데이터 추가
더보기
배열에 데이터를 추가하는 방법

1 . push

var arr = [1,2];
arr.push(3);

arr -> [1,2,3]

: 원본을 변경함

 

2. concate 

var arr2 = [1,2];

var result = arr2.concat(3);

result -> [1,2,3]
arr2 -> [1,2]

: 원본을 변경하지 않고 새로운 배열을 return

 

즉, push가 아닌 concat방법을 쓰는 것이 적절함 나중에 개발 시 퍼포먼스를 높일때 후자가 훨씬 좋음!

엄밀히 말하면 push/concat자체의 차이보다는 특정 값을 수정할 때는 원본을 수정하는 것이 아니라 복제를 만들어 수정한후 원본에 대입시켜 주는 것이 좋음 

 

concat방법 사용시 

else if(this.state.mode ==='create')
  {
    _article = <CreateContent onSubmit={function(_title,_desc){

      this.max_content_id = this.max_content_id+1; //1을 추가하여 id 부여 
      
      //concat방법을 이용하여 새로운 변수에 content를 저장 
      var _contents = this.state.contents.concat(
        {id:this.max_content_id, title:_title, desc:_desc}
        );

	  //새로 생성한 content를 state로 set
      this.setState(
        {
          contents : _contents
        }
      );

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

 

더보기

+추가 ) Push방법을 사용시 복제를 이용하는법

Array.from(this.state.contents)를 이용하여 원본의 복제를 생성 후 

복제에 값을 push해서 수정해준 후에 복제품을 원본에 대입하는 형식으로 변경

else if(this.state.mode ==='create')
  {
    _article = <CreateContent onSubmit={function(_title,_desc){

      this.max_content_id = this.max_content_id+1; //1을 추가하여 id 부여 
      
      //_contents변수에 복제를 생성 
      var _contents = Array.from(this.state.contents);
      
      //복제에 새로운 값을 push
      _contents.push({id:this.max_content_id, title:_title, desc:_desc});

	  //복제를 원본에 덮어씌워 수정
      this.setState(
        {
          contents : _contents
        }
      );

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

 

결과

새로 TOC가 추가된 모습

 

 

 

 

최종 

App.js

import React, { Component } from 'react';
import './App.css';
import TOC from "./components/TOC";
import Subject from "./components/Subject"
import ReadContent from './components/ReadContent';
import Control from './components/Control';
import CreateContent from './components/CreateContent';



class App extends Component {

  constructor(props){ 
    super(props); 
    this.max_content_id=3; //현재 최대 id값을 초기값으로 지정
    this.state ={
      mode : 'read',
      subject : {title:"WEB", sub:"world wide web!"},
      selected_content_id : 2,
      welcome : {title:"welcome", desc:"hello, react!"},
      contents : [
        {id:1, title:'HTML', desc:'HTML is for information'},
        {id:2, title:'CSS', desc:'CSS is for design'},
        {id:3, title:'JavaScript', desc:'JavaScript is for interactive'}
      ]
    }

  }


render(){
  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 i = 0;
    while(i<this.state.contents.length){
        var data = this.state.contents[i];
        if(data.id === this.state.selected_content_id){
          _title = data.title;
          _desc = data.desc;
          break;
        }
      i=i+1;
    }
    _article = <ReadContent title={_title} desc={_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;
      var _contents = this.state.contents.concat(
        {id:this.max_content_id, title:_title, desc:_desc}
        );
      this.setState(
        {
          contents : _contents
        }
      );
    }.bind(this)}></CreateContent> 
  }
    return (
      <div className="App">

        <Subject 
          title={this.state.subject.title} 
          sub={this.state.subject.sub}
          onChangePage={function(){
          this.setState({mode:'welcome'});
        }.bind(this)}
        ></Subject>

        <TOC onChangePage={function(id){

            this.setState({
              mode : 'read',
              selected_content_id : Number(id)
            });


        }.bind(this)}
        data={this.state.contents}></TOC>

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

        {_article}

      </div>
      );
  
}
}

export default App;

 

CreateContent.js

import React, { Component } from 'react';

class CreateContent extends Component{


    render(){
      return(
        <article>
          <h2>Create</h2>
          <form action="/create_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"></input></p>
                <p><textarea name="desc" placeholder="description"></textarea></p>
                <p><input type="submit"></input></p>
          </form>
        </article>
      );
    }
  }


  export default CreateContent; //외부에서 사용을 허용

 

ReadContent.js

import React, { Component } from 'react';

class ReadContent extends Component{


    render(){
      return(
        <article>
          <h2>{this.props.title}</h2>
            {this.props.desc}
        </article>
      );
    }
  }


  export default ReadContent; //외부에서 사용을 허용

 

Control.js

import React, { Component } from 'react';

class Control extends Component {
    render(){
      return(
        <ul>
        <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>

      );
    }
  }


export default Control; //외부에서 사용을 허용

 

 

 

참고영상

생활코딩

  • React - 19.1. create 구현 : 소개
  • React - 19.2. create 구현 : mode 변경 기능
  • React - 19.3. create 구현 : mode 전환 기능
  • React - 19.4. create 구현 : form
  • React - 19.5. create 구현 : onSubmit 이벤트
  • React - 19.6. create 구현 : contents 변경
  • React - 19.7. create 구현 : shouldComponentUpdate
  • React - 19.8. create 구현 : immutable

youtu.be/nwwJ2xU7E8w

 

728x90

'Frontend > React' 카테고리의 다른 글

[React] 마무리 정리 + 코드모음  (0) 2020.11.18
[React] Update, Delete기능 구현  (0) 2020.11.18
[React] Event  (0) 2020.11.18
[React] State  (0) 2020.11.17
[React] Component  (0) 2020.11.17