React

 

React - 생활코딩 1

 

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

 

자바스크립트에서 불변성(Immutability)이란

 

      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

 

 

 

 

 

 

 

 

 

react

 

about author

PHRASE

Level 60  라이트

꽃은 졌다가 피고, 피었다 또 진다. 비단 옷을 입었다가도 다시 베옷으로 바꿔 입게 된다. 재산이 많은 사람이라고 해서 언제까지나 반드시 부자는 아니며, 가난한 집이라 해서 늘 적막하지만은 않다. 사람을 부추켜 올린다 해도 푸른 하늘까지는 올릴 수 없고, 사람을 밀어뜨린다 해도 깊은 구렁에까지 떨어뜨리지는 못한다. 그대에게 권고하노니 모든 일을 하늘에 원망

댓글 ( 4)

댓글 남기기

작성