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