본문 바로가기

Frontend/React

[React] Update, Delete기능 구현

728x90

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

 

Update , Delete기능 구현

 

 

코드 정리 

먼저 시작전에 render내의 if-else문으로 content의 내용을 결정짓는 내용이 너무 길기 때문에

다른 함수로 분리한 후 -> getContent(){}

_article변수를 return값으로 뱉게하고, _article이 쓰이던 content부분에

getContent() 를 호출하도록 변경

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'}
      ]
    }

  }

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 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 _article;
}


render(){


    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>

        {this.getContent()}

      </div>
      );
  
}
}

export default App;

 

 

Update기능

Update : read + create 기능

원래 쓰여있던 내용을 불러옴 (read)

내용 수정 후 작성(변경 내용 반영) (create) 

 

1단계 기본적인 틀 만들기

Update는 Create와 유사하므로

CreateContent.js를 복사하여 이름만 UpdateContent.js로 변경한 파일을 생성해 주고

UpdateContent.js

import React, { Component } from 'react';

class UpdateContent extends Component{


    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"></input></p>
                <p><textarea name="desc" placeholder="description"></textarea></p>
                <p><input type="submit"></input></p>
          </form>
        </article>
      );
    }
  }


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

 

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';
import UpdateContent from './components/UpdateContent';


class App extends Component {

  constructor(props){ 
    //생략
  }

getContent(){

  var _title, _desc, _article = null;

  if(this.state.mode === 'welcome')
  {
    //생략
  }
  else if(this.state.mode === 'read')
  {
    //생략
  }
  else if(this.state.mode ==='create')
  {
    //생략
  }
  else if(this.state.mode ==='update')
  {
    _article = <UpdateContent 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)}></UpdateContent> 
  }

  return _article;
}


render(){


    return (
      <div className="App">

        //생략 

      </div>
      );
  
}
}

export default App;

App.js에서도 mode가 update인지 확인하는 부분을 create 부분과 동일하게 일단 추가해 준 후 

Component이름만 UpdateContent로 변경해줌 

 

 

2단계 본문 내용 불러오기 

Update 버튼을 눌렀을 때 form 태그에 update를 하려는 항목의 내용이 그대로 불려와야함 

현재 선택한 항목의 내용을 불러오는 것은 이미 read를 구현할 때 했던 것 ( 목차를 클릭하면 해당하는 id의 번호 출력)

App.js의 getContent()내의 내용 

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

 

이 부분을 여러번 사용할 것이니 함수로 따로 제작

getReadContent()

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;
      }
    i=i+1;
  }

}

data를 title, desc로 나누지 않고 그대로 data를 return

 

App.js의 getContent()내의 내용도 getReadContent함수를 사용하는 것으로 변경

else if(this.state.mode === 'read')
  {
    var _content = this.getReadContent();
    _article = <ReadContent title={_content.title} desc={_content.desc}></ReadContent> 
  }

함수를 사용해서 return 된 data를 _content변수에 저장한 후 ._title , ._desc에 접근해서 사용 

 

이제 제작된 getReadContent함수를 Update에 사용해서 불러온 후 <UpdateContent>의 속성(props)로 전달

App.js getContent()함수 내부 

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;
      var _contents = this.state.contents.concat(
        {id:this.max_content_id, title:_title, desc:_desc}
        );
      this.setState(
        {
          contents : _contents
        }
      );
    }.bind(this)}></UpdateContent> 
  }

 

본문내용을 보여주는 것은

props로 전달된 data.title을 value에 넣어주면 update를 눌렀을때 알맞는 content의 제목이 date로 잘 전달된 것을 확인 가능 

UpdateContent.js

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

 

 

 

3단계 본문 내용 수정

 

하지만 이 방법을 사용하면 수정이 불가능함

props의 데이터는 read only만 가능 -> 가변적인 데이터인 State로 prop를 바꾸어주어야함

 

UpdateContent.js

    constructor(props){
        super(props);
        this.state={
            title:this.props.data.title
        }
    }

Constructor를 추가하고 state에 title : this.props.data.title을 추가하여, data로 받아온 정보를 state화 시킴

 

onChange함수를 이용해서 State를 조작할 수 있음

UpdateContent.js

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

 e.target.value : e.target은 input tag 전체를 의미하고 value는 그에 적히는 값이므로 

title을 input tag에 적히는 값으로 변경해주는 onChange함수 + setState를 사용

 

+또한, value = {this.state.title}로 변경해주어야함 (prop는 변경이 불가능한 값이므로 state로 바꾸어줌)

 

 

desc인 textarea에도 그대로 적용해주면 됨

UpdateContent.js

import React, { Component } from 'react';

class UpdateContent extends Component{

    constructor(props){
        super(props);
        this.state={
            title:this.props.data.title,
            desc : this.props.data.desc
        }
    }

    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={function(e){
                       this.setState(
                           {title:e.target.value}
                       );
                    }.bind(this)}
                    ></input></p>
                <p><textarea 
                name="desc" 
                placeholder="description" 
                value={this.state.desc}
                onChange={function(e){
                    this.setState(
                        {desc:e.target.value}
                    )
                }}
                ></textarea></p>
                <p><input type="submit"></input></p>
          </form>
        </article>
      );
    }
  }


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

 

 

약간의 refactoring

onChange 함수를 밖으로 빼내서 중복을 제거

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

다음과 같이 만들어서 onChange함수 내에 대입

                <p><input 
                    type="text" 
                    name="title" 
                    placeholder="title"
                    value={this.state.title}
                    onChange={this.inputFormHandler.bind(this)}
                    ></input>
                </p>
                    
                <p><textarea 
                name="desc" 
                placeholder="description" 
                value={this.state.desc}
                onChange={this.inputFormHandler.bind(this)}
                ></textarea>
                </p>

 

.bind(this)를 항상 쓰지 않는 법 

    constructor(props){
        super(props);
        this.state={
            title:this.props.data.title,
            desc : this.props.data.desc
        }
        this.inputFormHandler = this.inputFormHandler.bind(this);
    }

이렇게 추가해주면 inputFromHandler를 사용할때 뒤에 bind(this)를 항상 붙이지 않아도 됨 

 

4단계 State 변경 ( 수정 내용 State에 반영)

 

UpdateContent.js

change가 발생하는 content의 id값을 알기위해 state추가 

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);
    }

 

form태그에 id부여 

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

id값은 수정하는 대상이 아니므로 hidden으로 설정해 보이지 않게함 

 

form을 submit시 id값을 함께 App 컴포넌트로 넘겨줌

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

 

 

App컴포넌트는 id값,title값,desc값을 넘겨받아서 

id값으로 수정을 원하는 content인지 확인한 후 맞으면 State의 content를 수정 (setState)

App.js

else if(this.state.mode ==='update')
  {
    _content = this.getReadContent();
    _article = <UpdateContent data={_content} onSubmit={function(_id,_title,_desc){
      //update content to this.state.contents
      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> 
  }

Array.from(this.state.contents) : array를 복제해서 생성  

//수정할때는 원본이 아닌 복제품을 수정해서 완료후 원본에 대입하는 방식을 써야함

 

while문을 이용해 content를 증가시키면서 수정을 원하는 id와 일치하면 복제한 contents를 수정

그 후 set State를 이용하여 state를 바꿔줌 

 

 

 

5단계 제출버튼 누른 후 read로 mode변경

제출 버튼을 누르면 update모드( form창이 보임) 가 아닌 read mode(본문 내용창)이 보이도록 설정

App.js

else if(this.state.mode ==='update')
  {
    _content = this.getReadContent();
    _article = <UpdateContent data={_content} onSubmit={function(_id,_title,_desc){
      //update content to this.state.contents
      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,
          mode : 'read'
        }
      );
    }.bind(this)}></UpdateContent> 
  }

setState부분에 mode : 'read'추가 

 

 

create시에도 똑같이 변경해줌 

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,
          mode : 'read',
          selected_content_id :this.max_content_id
        }
      );
    }.bind(this)}></CreateContent> 
  }

setState에

mode : 'read'를 추가하고 read시 현재 추가한 글을 보여지게 하도록 방금 추가한 id를 selected_content_id로 변경해줌 

 

 

 

전체코드

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';
import UpdateContent from './components/UpdateContent';


class App extends Component {

  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'}
      ]
    }

  }


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;
      }
    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){
      //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,
          mode : 'read',
          selected_content_id :this.max_content_id
        }
      );
    }.bind(this)}></CreateContent> 
  }
  else if(this.state.mode ==='update')
  {
    _content = this.getReadContent();
    _article = <UpdateContent data={_content} onSubmit={function(_id,_title,_desc){
      //update content to this.state.contents
      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,
          mode : 'read'
        }
      );
    }.bind(this)}></UpdateContent> 
  }

  return _article;
}


render(){


    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>

        {this.getContent()}

      </div>
      );
  
}
}

export default App;

 

 

UpdateContent.js

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

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

                <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"></input></p>
          </form>
        </article>
      );
    }
  }


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

 

 

Delete기능

Delete시에는 화면이 전환되지 않음 

따라서 if / else문을 이용해서 delete가 아닐 때만 setState mode : _mode로 변경시켜 Create/UpdateContent.js가 실행되도록 함

<Control onChangeMode={function(_mode){
          if(_mode === 'delete'){
            
          }else{
            this.setState({
              mode : _mode
            })
          }

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

 

정말 삭제할건지 물어보기

window.confirm

확인을 누르면 true, cancle을 누르면 false를 반환함 

즉, true일 때, while문을 selcted_content_id와 같은 id를 보유한 contents를 검사해 삭제함 

<Control onChangeMode={function(_mode){
          if(_mode === 'delete'){
            if(window.confirm("정말 삭제하실 건가요?")){
             //삭제
            }
          }else{
            this.setState({
              mode : _mode
            })
          }

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

 

splice(a,b)

a 번호부터 b개를 삭제해주는 함수 

<Control onChangeMode={function(_mode){
          if(_mode === 'delete'){
            if(window.confirm("정말 삭제하실 건가요?")){
              var _contents = Array.from(this.state.contents);
              var i = 0;
              while(i<_contents.length){
                if(_contents[i].id === this.state.selected_content_id)
                _contents.splice(i,1);
                break;
              }
              i = i + 1;
            }
            this.setState({
              mode:'welcome',
              contents:_contents
            })
          }else{
            this.setState({
              mode : _mode
            })
          }

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

물론 여기서도 복제한 Array를 이용해 삭제 한 후 setState를 이용하여 반영해줌

그 후 해당 게시글이 삭제되었으니 welcome모드로 변경해줌

 

alert로 삭제가 완료되었다는 문구출력

        <Control onChangeMode={function(_mode){
          if(_mode === 'delete'){
            if(window.confirm("정말 삭제하실 건가요?")){
              var _contents = Array.from(this.state.contents);
              var i = 0;
              while(i<_contents.length){
                if(_contents[i].id === this.state.selected_content_id){
                   _contents.splice(i,1);
                  break;
                }
              i = i + 1;
            }
            this.setState({
              mode:'welcome',
              contents:_contents
            })
            alert("삭제가 완료되었습니다.");
          }
          }else{
            this.setState({
              mode : _mode
            })
          }

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

 

 

 

정상적으로 삭제된 모습

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';
import UpdateContent from './components/UpdateContent';


class App extends Component {

  constructor(props){ 
    super(props); 
    this.max_content_id=3; 
    this.state ={
      mode : 'welcome',
      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'}
      ]
    }

  }


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;
      }
    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){
      //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,
          mode : 'read',
          selected_content_id :this.max_content_id
        }
      );
    }.bind(this)}></CreateContent> 
  }
  else if(this.state.mode ==='update')
  {
    _content = this.getReadContent();
    _article = <UpdateContent data={_content} onSubmit={function(_id,_title,_desc){
      //update content to this.state.contents
      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,
          mode : 'read'
        }
      );
    }.bind(this)}></UpdateContent> 
  }

  return _article;
}


render(){


    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){
          if(_mode === 'delete'){
            if(window.confirm("정말 삭제하실 건가요?")){
              var _contents = Array.from(this.state.contents);
              var i = 0;
              while(i<_contents.length){
                if(_contents[i].id === this.state.selected_content_id){
                   _contents.splice(i,1);
                  break;
                }
              i = i + 1;
            }
            this.setState({
              mode:'welcome',
              contents:_contents
            })
          }
          }else{
            this.setState({
              mode : _mode
            })
          }

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

        {this.getContent()}

      </div>
      );
  
}
}

export default App;

 

 

참고영상

생활코딩

  • React - 20.1 update 구현 
  • React - 20.2 update 구현 : form
  • React - 20.3 update 구현 : state변경
  • React - 21 delete 구현

youtu.be/YKdebEty6uQ

 

728x90

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

[React] 유형테스트 만들기(1) - 기획  (0) 2021.03.02
[React] 마무리 정리 + 코드모음  (0) 2020.11.18
[React] Create기능 구현  (0) 2020.11.18
[React] Event  (0) 2020.11.18
[React] State  (0) 2020.11.17