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)
댓글 남기기