5. Create 기능 구현
18. 베이스 캠프
부모 컴포넌트에서 자식 컴포넌테에 데이터를 넘겨주는 방법은 props
자식 컴포넌트에서 부모컴포넌트에 데이터를 넘겨주는 방법은 이벤트로 넘겨준다.
19-1. create 구현 : 소개
19-2.create 구현 : mode 변경 기능
App.js
import './App.css';
import { 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: "www!" },
      welcome: { title: "welcome", desc: "Hello, React!!" },
      contents: [
        { id: 1, title: "1.HTML", desc: "HTML is for information" },
        { id: 2, title: "2.CSS", desc: "CSS is for design" },
        { id: 3, title: "3.javaScript", desc: "javaScript is for interactive" },
      ]
    }
  }
  render() {
    // console.log("App render");
    let _title, _desc = null;
    if (this.state.mode === "welcome") {
      _title = this.state.welcome.title;
      _desc = this.state.welcome.desc;
    } else if (this.state.mode === "read") {
     
      const data = this.state.contents.filter(item => {
        return this.state.selected_content_id === item.id
      })[0];
      // console.log("data", data);
      _title = data.title;
      _desc = data.desc;
    }
    return (
      <div className="App">
        <Subject
          title={this.state.subject.title}
          sub={this.state.subject.sub}
          onChangePage1={function () {
            alert("hihihi1");
            this.setState({
              mode: "welcome"
            })
          }.bind(this)}
        />
        <TOC onChangePage={function (id) {
          //console.log("event :", id);
          this.setState({
            mode: "read",
            selected_content_id: Number(id)
          });
        }.bind(this)} data={this.state.contents} />
        <Control
          onChangeMode={function (_mode) {
            console.log("onChangeMode ", _mode);
            this.setState({
              mode: _mode
            })
          }.bind(this)}
        />
        <Content title={_title} desc={_desc} />
      </div >
    );
  }
}
export default App;
Control.js
import { Component } from 'react';
class Control extends Component {
    render() {
        console.log("Control 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 type="button" onClick={function (e) {
                    e.preventDefault();
                    this.props.onChangeMode("delete");
                }.bind(this)} value="delete"></input></li>
            </ul>
        )
    }
}
export default Control;
19-3.create 구현 : mode 전환 기능
App.js
import './App.css';
import { Component } from 'react';
import TOC from './components/TOC';
import ReadContent from './components/ReadContent';
import Subject from './components/Subject';
import Control from './components/Control';
import CreateContent from './components/CreateContent';
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mode: "read",
      selected_content_id: 2,
      subject: { title: "WEB", sub: "www!" },
      welcome: { title: "welcome", desc: "Hello, React!!" },
      contents: [
        { id: 1, title: "1.HTML", desc: "HTML is for information" },
        { id: 2, title: "2.CSS", desc: "CSS is for design" },
        { id: 3, title: "3.javaScript", desc: "javaScript is for interactive" },
      ]
    }
  }
  render() {
    // console.log("App render");
    let _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} />
    } else if (this.state.mode === "read") {
      // let i = 0;
      // while (i < this.state.contents.length) {
      //   const data = this.state.contents[i];
      //   if (this.state.selected_content_id === data.id) {
      //     console.log("data", data);
      //     _title = data.title;
      //     _desc = data.desc;
      //     break;
      //   }
      //   i++;
      // }
      const data = this.state.contents.filter(item => {
        return this.state.selected_content_id === item.id
      })[0];
      // console.log("data", data);
      _title = data.title;
      _desc = data.desc;
      _article = <ReadContent title={_title} desc={_desc} />
    } else if (this.state.mode === "create") {
      _article = <CreateContent />
    }
    return (
      <div className="App">
        <Subject
          title={this.state.subject.title}
          sub={this.state.subject.sub}
          onChangePage1={function () {
            //alert("hihihi1");
            this.setState({
              mode: "welcome"
            })
          }.bind(this)}
        />
        <TOC onChangePage={function (id) {
          //console.log("event :", id);
          this.setState({
            mode: "read",
            selected_content_id: Number(id)
          });
        }.bind(this)} data={this.state.contents} />
        <Control
          onChangeMode={function (_mode) {
            console.log("onChangeMode ", _mode);
            this.setState({
              mode: _mode
            })
          }.bind(this)}
        />
        {_article}
      </div >
    );
  }
}
export default App;
CreateContent.js
import { Component } from 'react';
class CreateContent extends Component {
    render() {
        // console.log("Content render");
        return (
            <article>
                <h1>CreateContent</h1>
            </article>
        );
    }
}
export default CreateContent;
19-4.create 구현 : form
CreateContent.js
import { Component } from 'react';
class CreateContent extends Component {
    render() {
        // console.log("Content 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' />
                    </p>
                    <p>
                        <textarea name="desc" placeholder='description'></textarea>
                    </p>
                    <p>
                        <input type="submit" />
                    </p>
                </form>
            </article>
        );
    }
}
export default CreateContent;
19-5.create 구현 : onSubmit 이벤트
App.js
~
    _article = <ReadContent title={_title} desc={_desc} />
    } else if (this.state.mode === "create") {
      _article = <CreateContent
        onSubmit={function (_title, _desc) {
          //add content to this.state.contents
          console.log("자식컴포넌트 CreateContent 데이터 받기 : ", _title, _desc);
        }.bind(this)}
      />
    }
~
CreateContent.js
import { Component } from 'react';
class CreateContent extends Component {
    render() {
        // console.log("Content render");
        return (
            <article>
                <h2>Create</h2>
                <form action="/create_process" method="post" onSubmit={function (e) {
                    e.preventDefault();
                    console.log("form 데이터 전송 :", e.target.title.value, e.target.desc.value);
                    this.props.onSubmit(e.target.title.value, e.target.desc.value);
                }.bind(this)}>
                    <p>
                        <input type="text" name="title" placeholder='title' />
                    </p>
                    <p>
                        <textarea name="desc" placeholder='description'></textarea>
                    </p>
                    <p>
                        <input type="submit" />
                    </p>
                </form>
            </article>
        );
    }
}
export default CreateContent;
19-6. create 구현 : contents 변경
push 같은 얕은 복사가 아닌 다음과 같은 형식으로 데이터 깊은 복사 를 한다.
1) concat
2)filter
3) map
4) slice
5)spread 스프레드(전개) 연산자
깊은 복사 참조 : https://macaronics.net/index.php/m04/react/view/1878
 } else if (this.state.mode === "create") {
      _article = <CreateContent
        onSubmit={function (_title, _desc) {
          //add content to this.state.contents
          console.log("자식컴포넌트 CreateContent 데이터 받기 : ", _title, _desc);
          this.max_content_id = this.max_content_id + 1;
          const _contents = this.state.contents.concat(
            { id: this.max_content_id, title: _title, desc: _desc }
          );
          this.setState({
            contents: _contents
          });
        }.bind(this)
        }
      />
    }
19-7.create 구현 : shouldComponentUpdate
1) render() 이전에 shouldComponentUpdate 실행된다.
2)shouldComponentUpdate return 값이 true 면 render() 호출 되고 false 면 호출 되지 않는다.
3) 데이터 추가시 shouldComponentUpdate(newProps, newState)
this.props.data; 현재값 이고, newProps 추가된 값이다.
데이터는 얖은 복사가 아닌 다음과 같은 깊은 복사로 할것
1) concat 2)filter 3) map 4) slice 5)spread 스프레드(전개) 연산자
TOC.js
import { Component } from 'react';
class TOC extends Component {
    shouldComponentUpdate(newProps, newState) {
        console.log("====>TOC render shouldComponentUpdate ", newProps, this.props.data);
        //1) render() 이전에 shouldComponentUpdate 실행된다.
        //2)shouldComponentUpdate return 값이 true 면 render() 호출 되고 false 면 호출 되지 않는다.
        //3) 데이터 추가시 shouldComponentUpdate(newProps, newState) 
        //this.props.data; 현재값 이고, newProps 추가된 값이다.
        if (this.props.data === newProps.data) {
            return false;
        }
        return true;
    }
    render() {
        console.log("TOC render");
        let lists = [];
        const data = this.props.data;
        let i = 0;
        while (i < data.length) {
            lists.push(
                <li key={data[i].id}><a href={"/content/" + data[i].id}
                    data-id={data[i].id}
                    onClick={function (id, e) {
                        e.preventDefault();
                        //const id = e.target.dataset.id;
                        // console.log("id : ", id);
                        this.props.onChangePage(id);
                        //bind 에 파라미터 값을 추가하면 this event 값은 한칸씩 뒤로 밀린다.
                    }.bind(this, data[i].id)}
                >{data[i].title}</a></li>
            );
            i = i + 1;
        }
        return (
            <nav>
                <ul>
                    {lists}
                </ul>
            </nav>
        );
    }
}
export default TOC;
19-8. create 구현 : immutable
      this.max_content_id = this.max_content_id + 1;
          //let newContents = Array.from(this.state.contents);
          // this.state.contents.push(
          //   { id: this.max_content_id, title: _title, desc: _desc }
          // );
          const _contents = this.state.contents.concat(
            { id: this.max_content_id, title: _title, desc: _desc }
          );
6. Update & Delete 기능 구현
20-1. update 구현
App.js
import './App.css';
import { Component } from 'react';
import TOC from './components/TOC';
import ReadContent from './components/ReadContent';
import Subject from './components/Subject';
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: "create",
      selected_content_id: 2,
      subject: { title: "WEB", sub: "www!" },
      welcome: { title: "welcome", desc: "Hello, React!!" },
      contents: [
        { id: 1, title: "1.HTML", desc: "HTML is for information" },
        { id: 2, title: "2.CSS", desc: "CSS is for design" },
        { id: 3, title: "3.javaScript", desc: "javaScript is for interactive" },
      ]
    }
  }
  getReadContent() {
    return this.state.contents.filter(item => {
      return this.state.selected_content_id === item.id
    })[0];
  }
  getContent() {
    let _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} />
    } else if (this.state.mode === "read") {
      const _content = this.getReadContent();
      _article = <ReadContent title={_content.title} desc={_content.desc} />
    } else if (this.state.mode === "create") {
      _article = <CreateContent
        onSubmit={function (_title, _desc) {
          //add content to this.state.contents
          console.log("자식컴포넌트 CreateContent 데이터 받기 : ", _title, _desc);
          this.max_content_id = this.max_content_id + 1;
          const _contents = this.state.contents.concat(
            { id: this.max_content_id, title: _title, desc: _desc }
          );
          this.setState({ contents: _contents });
        }.bind(this)
        }
      />
    } else if (this.state.mode === "update") {
      const _content = this.getReadContent();
      _article = <UpdateContent data={_content} />
    }
    return _article;
  }
  render() {
    // console.log("App render");
    return (
      <div className="App">
        <Subject
          title={this.state.subject.title}
          sub={this.state.subject.sub}
          onChangePage1={function () {
            //alert("hihihi1");
            this.setState({
              mode: "welcome"
            })
          }.bind(this)}
        />
        <TOC onChangePage={function (id) {
          //console.log("event :", id);
          this.setState({
            mode: "read",
            selected_content_id: Number(id)
          });
        }.bind(this)} data={this.state.contents} />
        <Control
          onChangeMode={function (_mode) {
            console.log("onChangeMode", _mode);
            this.setState({
              mode: _mode
            })
          }.bind(this)}
        />
        {this.getContent()}
      </div >
    );
  }
}
export default App;
UpdateContent.js
import { Component } from 'react';
class UpdateContent extends Component {
    render() {
        console.log(this.props.data);
        console.log("UpdateContent 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' />
                    </p>
                    <p>
                        <textarea name="desc" placeholder='description'></textarea>
                    </p>
                    <p>
                        <input type="submit" />
                    </p>
                </form>
            </article>
        );
    }
}
export default UpdateContent;
20-2. update 구현 : form
UpdateContent.js
import { Component } from 'react';
class UpdateContent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            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(this.props.data);
        //console.log("UpdateContent 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={this.inputFormHandler}
                        />
                    </p>
                    <p>
                        <textarea name="desc" placeholder='description'
                            onChange={this.inputFormHandler}
                            value={this.state.desc}></textarea>
                    </p>
                    <p>
                        <input type="submit" />
                    </p>
                </form>
            </article>
        );
    }
}
export default UpdateContent;
20-3. update 구현 : state 변경
App.js
import './App.css';
import { Component } from 'react';
import TOC from './components/TOC';
import ReadContent from './components/ReadContent';
import Subject from './components/Subject';
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: "create",
      selected_content_id: 2,
      subject: { title: "WEB", sub: "www!" },
      welcome: { title: "welcome", desc: "Hello, React!!" },
      contents: [
        { id: 1, title: "1.HTML", desc: "HTML is for information" },
        { id: 2, title: "2.CSS", desc: "CSS is for design" },
        { id: 3, title: "3.javaScript", desc: "javaScript is for interactive" },
      ]
    }
  }
  getReadContent() {
    return this.state.contents.filter(item => {
      return this.state.selected_content_id === item.id
    })[0];
  }
  getContent() {
    let _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} />
    } else if (this.state.mode === "read") {
      const _content = this.getReadContent();
      _article = <ReadContent title={_content.title} desc={_content.desc} />
    } else if (this.state.mode === "create") {
      _article = <CreateContent
        onSubmit={function (_title, _desc) {
          //add content to this.state.contents
          console.log("자식컴포넌트 CreateContent 데이터 받기 : ", _title, _desc);
          this.max_content_id = this.max_content_id + 1;
          const _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)
        }
      />
    } else if (this.state.mode === "update") {
      const _content = this.getReadContent();
      _article = <UpdateContent data={_content}
        onSubmit={
          function (_id, _title, _desc) {
            //map 은 깊은 복사 가능
            const _contents = this.state.contents.map((item) => {
              if (item.id === _id) {
                return { id: _id, title: _title, desc: _desc };
              } else return item;
            });
            this.setState({ contents: _contents, mode: "read" });
          }.bind(this)
        }
      />
    }
    return _article;
  }
  render() {
    // console.log("App render");
    return (
      <div className="App">
        <Subject
          title={this.state.subject.title}
          sub={this.state.subject.sub}
          onChangePage1={function () {
            //alert("hihihi1");
            this.setState({
              mode: "welcome"
            })
          }.bind(this)}
        />
        <TOC onChangePage={function (id) {
          //console.log("event :", id);
          this.setState({
            mode: "read",
            selected_content_id: Number(id)
          });
        }.bind(this)} data={this.state.contents} />
        <Control
          onChangeMode={function (_mode) {
            console.log("onChangeMode", _mode);
            this.setState({
              mode: _mode
            })
          }.bind(this)}
        />
        {this.getContent()}
      </div >
    );
  }
}
export default App;
21-delete 구현
App.js
        <Control
          onChangeMode={function (_mode) {
            if (_mode === "delete") {
              if (window.confirm("정말 삭제 하시겠습니까?")) {//삭제 처리                
                const _contents = this.state.contents.filter(n => {
                  return n.id !== this.state.selected_content_id;
                });
                this.setState({ contents: _contents, mode: "welcome" });
              }
            } else {
              this.setState({ mode: _mode });
            }
          }.bind(this)}
        />
22.수업을 마치며
소스 : https://github.com/braverokmc79/LifeCoding














댓글 ( 4)  
댓글 남기기