👀 React를 사용해서 어떠한 방식으로 Create 할 것인가?
🖐 정적으로 출력되어있던 메뉴들을 동적으로 추가해보자!
" 아래 사진과 같은 controll Button을 생성하여 클릭시 mode 를 변경해주자 "
//App.js <TOC> 태그 아래
<Control onChangeMode={function (_mode) {⭐//받은 값을 setState를 사용하여 mode값 변경
this.setState({ mode: _mode });
}.bind(this)}></Control>
//Control.js
class Control extends Component {
render() {
return (
<ul>
<li><a href="/create" onClick={function(e){
e.preventDefault();
this.props.onChangeMode('create');⭐// create 값 넘겨주기
}.bind(this)}>create</a></li>
<li><a href="/update" onClick={function(e){
e.preventDefault();
this.props.onChangeMode('update');⭐// update 값 넘겨주기
}.bind(this)}>update</a></li>
<li><input onClick={function(e){
e.preventDefault();
this.props.onChangeMode('delete');⭐// delete 값 넘겨주기
}.bind(this)} type='button' value='delete'></input></li>
</ul>
);
}
}
" mode가 변환됨에 따라서 Content 영역의 내용이 변경되는 코드를 구현해보자 "
👉 이전 Content를 ReadContent로 변경하고, mode가 create일 경우 CreateContent를 출력하는 코드
//App.js
render() {
var _title, _desc, _article = null;
if (this.state.mode === 'welcome') {
_title = this.state.welcome.title;
_desc = this.state.welcome.desc;
⭐//mode가 welcome일 경우 ReadContent를 출력하기 위한 코드
_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 += 1;
}
⭐//mode가 read일 경우 ReadContent를 출력하기 위한 코드
_article = <ReadContent title={_title} desc={_desc}></ReadContent>;
⭐//mode가 create일 경우 CreateContent를 출력하기 위한 코드
⭐//상단에서 CreateContent를 import 해야함!!
} else if (this.state.mode === 'create') {
_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>
⭐//원래 contents 영역이였던 부분을 _article로 변경한다.
{_article}
</div>
);
}
" form 내의 내용을 구성한다 "
//CreateContent.js
class CreateContent extends Component {
render() {
return (
<article>
<h2>Create</h2>
<form action="/create_process" method="post"
onSubmit={function(e){ ⭐//html의 기능
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" value="submit"></input></p>
</form>
</article>
);
}
}
" form에서 입력한 값을 onSubmit 이벤트를 사용하여 App.js로 넘겨준다 "
//CreateContent.js
<form action="/create_process" method="post"
onSubmit={function (e) { ⭐//html의 기능
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" value="submit"></input></p>
</form>
//App.js
} else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function(_title,_desc){⭐//값을 받아옴
this.setState({
contents:{}
});
}.bind(this)}></CreateContent>;
}
//App.js
} else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function (_title, _desc) {
this.max_content_id += 1;
this.state.contents.⭐push⭐(
{ id: this.max_content_id, title: _title, desc: _desc }
);
this.setState({
contents: this.state.contents
});
}.bind(this)}></CreateContent>;
}
//App.js
} else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function (_title, _desc) {
this.max_content_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나 conact 아무것이나 사용하여도 상관이 없을 수도 있으나, 나중에 프로그램이 확장하게 된다면 concat 을 사용하는 것이 바람직하다.
" push와 concat의 연장선 "
shouldcomponentUpdate
: 계속해서 호출되는 TOC의 render() 함수, 이 함수를 재사용하지 않고 변화된 것이 있을 경우에만 render() 함수를 호출시킬 수 있는 함수
//TOC.js
class TOC extends Component {
⭐//sholdcomponentUpdate를 사용하면 재호출시에 이곳으로 먼저 도달하게 된다
shouldComponentUpdate(newProps, newState) {
console.log(newProps.data, this.props.data);
if (this.props.data === newProps.data) {
return false; ⭐//false인 경우 여기서 멈추지만
} else {
return true; ⭐//true인 경우 다시 한번 실행된다
}
}
render() {
var list = [];
//~
" 원본을 바꾸지 않고, setState를 사용하는 법! 즉, 원본이 불변한다. "
Array.from({복제할 배열})
//example Code
var a=[1,2];
//복제하는 부분
var b=Array.from(a);
//a와 b가 같음에도 다른 배열로 인식(false)
console.log(a,b,a===b);
//a와는 관계가 없는 b라는 배열을 가공할 수 있음
b.push(3);
console.log(a,b,a===b);
=====(Result)=====
VM576:3 (2) [1, 2] (2) [1, 2] false
VM576:5 (2) [1, 2] (3) [1, 2, 3] false
Object.assign({복제할 객체})
//example Code
var a={name : "glenn"};
//객체를 복제하는 부분
var b=Object.assign({},a);
//배열과 마찬가지로 false
console.log(a,b,a===b);
//a와는 관계없는 b의 name 값 변
b.name="hello JavaScript";
console.log(a,b,a===b);
=====(Result)=====
VM988:3 {name: "glenn"} {name: "glenn"} false
VM988:5 {name: "glenn"}
{name: "hello JavaScript"} false
//적용 코드 App.js
} else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function (_title, _desc) {
//add content to this.state.contents
this.max_content_id += 1;
//배열 복제
var newContents = Array.from(this.state.contents);
//가공
newContents.push(
{ id: this.max_content_id, title: _title, desc: _desc }
);
this.setState({
//적용
contents: newContents
});
}.bind(this)}></CreateContent>;
}