본문 바로가기

Web/React

Create 구현

props vs state

Props State
read-only asynchronous
can not be modified can be modified using this.setState

- 상위 component가 하위 component에 명령할 때 Props를 사용하고, 하위 component가 상위 component에

  명령할 때는 이벤트를 사용한다.

- Props는 read-only. 자신의 하위에 포함된 것들은 변경할 수 있지만, 자신의 상위에 포함된 것들은 변경할 수 없다.

  이 경우 이벤트를 사용해 간접적으로 명령해 바꾼다.

 

- props는 상위 component가 하위 component에게 데이터 값만 전달하는 반면, state는 component 내부에서

  선언해 이벤트를 생성, 변경한다.

 

 

 

 

 

<Create>

1) mode 변경

import React, { Component } from 'react';
import TOC from "./components/TOC";
import Content from "./components/Content";
import Subject from "./components/Subject";
import Control from "./components/Control";


class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mode:'read',
      selected_content_id:2,
      subject:{title:'WEB', sub:"World Wide Web!"},
      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 = null;
    if(this.state.mode === 'welcome') {
      _title = this.state.welcome.title;
      _desc = this.state.welcome.desc;
    }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;
      }
    }
  return (
    <div className="App">
      <Subject
        title={this.state.subject.title}
        sub={this.state.subject.sub}
        onClickPage={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>
      <Content title={_title} desc={_desc}></Content>
    </div>
   );
 }
} 

export default App;
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;

- Control이라는 component를 만들어 create, update, delete를 누를 수 있게 만든다.(delete는 button)

- onChangeMode 이벤트를 활용해 create, update, delete를 누를 때마다 해당 mode로 state값이 바뀌게 한다.

 

 

 

 

2) mode 전환

 

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


class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mode:'read',
      selected_content_id:2,
      subject:{title:'WEB', sub:"World Wide Web!"},
      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">
      <Subject
        title={this.state.subject.title}
        sub={this.state.subject.sub}
        onClickPage={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;
import React, { Component } from 'react';
class ReadContent extends Component {
    render() {
      return (
        <article>
              <h2>{this.props.title}</h2>
               {this.props.desc}
        </article> 
      );
    }
  }

  export default ReadContent;
import React, { Component } from 'react';
class CreateContent extends Component {
    render() {
      return (
        <article>
              <h2>Create</h2>
              <form>

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

  export default CreateContent;

- mode가 전환되면 content값이 해당 mode의 content로 바뀌게 한다.(mode가 read면 read content로,

  mode가 create면 create content로 바뀌게)

- _article이라는 변수 만들어 mode마다 바뀌는 content 핸들링할 수 있게 한다.

 

 

 

 

3) form

CreateContent  component의 비워뒀던 form을 채우자

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();
                alert('Submit!!!');
              }.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;

- textarea: 입력할 text가 여러 줄일 때 사용

 

 

 

 

4) onSubmit 이벤트

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


class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mode:'create',
      selected_content_id:2,
      subject:{title:'WEB', sub:"World Wide Web!"},
      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) {
        console.log(_title, _desc);
      }.bind(this)}></CreateContent>
    }
  return (
    <div className="App">
      <Subject
        title={this.state.subject.title}
        sub={this.state.subject.sub}
        onClickPage={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;
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();
                debugger;
                this.props.onSubmit(
                  e.target.title.value,
                  e.target.desc.value
                );
                alert('Submit!!!');
              }.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;

- CreateContent component에서 e.target 활용- App.js CreateContent에 onClick 이벤트 추가

 

 

 

 

5) Contents 변경

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


class App extends Component {
  constructor(props) {
    super(props);
    this.max_content_id = 3;
    this.state = {
      mode:'create',
      selected_content_id:2,
      subject:{title:'WEB', sub:"World Wide Web!"},
      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) {
        this.max_content_id = this.max_content_id+1;
        // 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}
        )
        this.setState({
          contents:_contents
        });
        console.log(_title, _desc);
      }.bind(this)}></CreateContent>
    }
  return (
    <div className="App">
      <Subject
        title={this.state.subject.title}
        sub={this.state.subject.sub}
        onClickPage={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;

- state에 값을 추가할 때는 push와 같이 original data를 변경하는 것을 쓰지 말고, concat처럼 original data를   변경하지 않고 새로운 data를 추가하는 것을 쓴다.