<TOC>
와 <Content>
컴포넌트 사이에 create, update, delete 버튼 만들기class Control extends Component {
render() {
return (
<ul>
<li><a href="/create" onClick={function(e){ // 클릭 시 onChangeMode 핸들러 실행되게 하는 코드
e.preventDefault();
this.props.onChangeMode('create'); // 호출 시 mode값 전달하기
}.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>
);
}
}
import Control from "./components/Control";
<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 state값 바꾸기
mode: _mode
});
}.bind(this)}></Control>
<Content title={_title} desc={_desc}></Content>
<CreateContent>
컴포넌트로 바꿔보기import CreateContent from './components/CreateContent';
import UpdateContent from './components/UpdateContent';
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') { // mode가 'create'일 때 CreateContent 나오게 하기
_article = <CreateContent></CreateContent>
}
return (
<div className="App">
<Subject
title={this.state.subject.title}
sub={this.state.subject.sub}
onChangePage={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}
//가변적으로 바꾸기 위해 _article변수 사용
</div>
);
}
import React, { Component } from 'react';
class CreateContent extends Component {
render() {
return (
<article>
<h2>Create</h2>
<form action="/create_process" method="post"
// 사용자가 데이터 추가, 수정 시 method를 post 방식을 써야 url 노출x
onSubmit={function (e) { // Submit 버튼 클릭 시 폼 태그에 포함되어 있는 onSubmit 이벤트 실행
e.preventDefault();
}.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;
else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function (_title, _desc) {
// add content to this.state.contents
}.bind(this)}></CreateContent>
}
<form action="/create_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"></input></p>
<p><textarea name="desc" placeholder="description"></textarea></p>
<p><input type="submit"></input></p>
</form>
e.target은 form 자체를 가리킴
value는 입력한 값을 가져올 수 있기 때문에 _title, _desc 인자로 값을 넘겨줌
class App extends Component {
constructor(props) {
super(props);
⭐this.max_content_id = 3; // state값이 아닌 이유는 UI에 아무런 영향을 주지 않기 때문
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() {
...
else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function (_title, _desc) {
this.max_content_id = this.max_content_id + 1; // 원래 있던 id값을 1 증가
⭐var _contents = this.state.contents.concat(
{ id: this.max_content_id, title: _title, desc: _desc }
)
this.setState({
contents: _contents
});
}.bind(this)}></CreateContent>
}
}
- 왜 push가 아닌 concat으로 배열 추가를 했을까?
- push는 원본배열 값이 바뀜, concat은 원본을 바꾸지 않고 원본을 변경한 새로운 배열 리턴var a = [1, 2]; a.push(3); console.log(a); [1, 2, 3]
var a = [1, 2]; var b = a.concat(3); console.log(a, b); [1, 2] [1, 2, 3] => 원본이 바뀌지 않음
class TOC extends Component {
shouldComponentUpdate(newProps, newState){ //- TOC 컴포넌트의 Props와 State값이 바뀐 값을 매개변수로 준다
if(this.props.data === newProps.data){
return false; // 현재 props와 바뀐 props가 같다면 함수 호출 x -->
}
return true; //그렇지 않다면 render() 호출
}
}
🔥그렇기 때문에 concat을 쓰지 않고 push를 썼다면?
원본이 바뀌어 이전값, 바뀐값이 같아져서 shouldComponentUpdate()를 쓰지 못함.
var a = [1, 2];
var b = Array.from(a);
console.log(a, b, a===b);
=> [1, 2] [1, 2] false
b.push(3);
console.log(a, b, a===b);
=> [1, 2] [1, 2, 3] false
a,b는 내용이 같을 뿐 완전히 다름
var newContents = Array.from(this.state.contenst);
newContents.push({id:this.max_content_id, title:_title, desc:_desc});
this.setState({
contents: newContents
});
var a = { name: 'egoing' };
var b = Object.assign({}, a);
console.log(a, b, a === b);
=> {name: "egoing"} {name: "egoing"} false
b.name = 'leezche';
console.log(a, b, a === b);
=> {name: "egoing"} {name: "leezche"} false
a, b는 내용이 같지만 같은 객체가 아님