Mode 변경
TOC 컴포넌트 아래에 create, update, delete 구현하기
create, update는 눌렀을때 특정 페이지로 이동해서 실행되게 하고 delete는 눌렀을때 페이지 이동 없이 실행되게 함
delete에 link를 사용하게 되면, 사용자들이 어떤 페이지를 방문할 때 페이지가 삭제될 수도 있는 큰 문제가 발생하기 때문에 페이지 개념이 아니라 버튼으로 구현
components 디렉토리에 Control.js 생성
App.js
<Control onChangeMode={function(_mode){ //호출 시 mode 값 변경
this.setState({
mode:_mode
});
}.bind(this)}></Control>
<Content title={_title} desc={_desc}></Content>
Control.js
import React, { Component } from 'react';
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>
);
}
}
export default Control;
Mode 전환
create 클릭했을 때, CreateContent 컴포넌트 생성하기
원래 있던 Content 파일을 ReadContent로 바꾸고 CreateContent 파일 생성
App.js
import React, { Component } from 'react';
import './App.css';
import TOC from "./components/TOC";
import CreateContent from "./components/CreateContent"
import ReadContent from "./components/ReadContent";
import Subject from "./components/Subject";
import Control from "./components/Control";
class App extends Component {
constructor(props) {
super(props);
this.state = {
mode: 'welcome',
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 Hyper Text Markup Language' },
{ id: 2, title: 'CSS', desc: 'CSS is for design' },
{ id: 3, title: 'JavaScript', desc: 'JS is for interactive' },
]
}
}
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) //TOC.js에서 id값을 가져옴
});
}.bind(this)} data={this.state.contents}
></TOC>
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode
});
}.bind(this)}></Control>
{_article} // 위에 _article= <ReadContent title={_title} desc={_desc}></ReadContent>
</div>
);
}
}
export default App;
Form 구현
CreateContent.js
class CreateContent extends Component {
render() {
return (
<article>
<h2>Create</h2>
<form action="/create_process" method="post" // create_process 페이지로 사용자가 입력한 정보를 전달
onSubmit={function(e){
e.preventDefault();
}.bind(this)}>
<p><input type="text" name="title" placeholder="title"></input></p>
<p>
<textarea name="desc" placeholder="description"></textarea> //textarea : 사용자가 입력할 텍스트가 여러줄일 때 사용
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
)
}
}
from 태그에선 submit 했을 때, action으로 설정한 페이지로 화면이 이동됨
onSubmit : submit 버튼 클릭하면 설정한 이벤트가 실행 되도록함 -> e.preventDefault로 기본 동작인 페이지가 이동하는걸 막아줌
onSubmit 이벤트
submit 버튼을 눌렀을 때, CreateContent에 이벤트로 설치된 함수를 실행시켜 사용자가 입력한 값을 App 컴포넌트의 Contents로 추가하기
App.js
else if(this.state.mode === 'create'){
_article =<CreateContent onSubmit={function(_title, _desc){
//add content to this.state.contents
}.bind(this)}></CreateContent>
}
CreateContent.js
<form action="/create_process" method="post"
onSubmit={function (e) {
e.preventDefault();
this.props.onSubmit(
e.target.title.value,
e.target.desc.value // target이 form을 가리킴
);
}.bind(this)}
>
value의 값을 각각 _title, _desc 인자로 전달
Content 변경
App 컴포넌트의 Contents에 데이터 추가하기
class App extends Component {
constructor(props) {
super(props);
this.max_content_id = 3; // UI에 아무런 영향을 주지 않기 때문에 state로 안해도 됨
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을 이용
state에다 값을 추가할때는 push와 같이 원본 데이터를 바꾸는 것을 사용하지 마라
기존에 있던 데이터에 값을 하나씩 추가하는 방식 -> 나중에 성능 개선할때 매우 까다로워짐
shouldComponentUpdate
app.js에 contents 값이 바뀔때마다 TOC 컴포넌트의 render 함수가 호출되어 TOC가 다시 랜더링됨
근데 contents가 바뀌지 않을때에도 TOC가 랜더링됨
-> 자기랑 상관없는 일이 진행되는 것은 불합리. 작은 프로그램에서는 상관없는데 큰 프로그램에선 이슈가 될수도
TOC.js
class TOC extends Component {
shouldComponentUpdate(newProps, newState){
if(this.props.data === newProps.data){
return false;
}
return true;
}
shouldComponentUpdate() 함수
컴포넌트의 render 함수가 실행되지 않을지를 결정할 수 있음
newProps, newState 두 개의 매개변수를 가질 수 있음
newProps.data ->바뀐값, this.props.data ->바뀌기 전의 값
false를 반환하면 render함수가 호출되고 true를 반환하면 render 함수가 호출됨
Immutable
원본이 변하지 않는다. 불변성
배열
var a = [1, 2];
var b = Array.from(a);
console.log(a, b, a===b);
=> [1, 2] [1, 2] false // 내용이 같을 뿐, 완전 다른 배열임
concat 말고 push를 사용하고 싶다면 Array.from( ) 사용하면 됨
객체
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는 내용이 같지만 다른 객체
Object.assign 을 통해서 객체를 복제할 수 있다. 하지만 내용만 같고 다른 객체임
'programming > React' 카테고리의 다른 글
useEffect (0) | 2021.08.03 |
---|---|
클래스형 컴포넌트 vs 함수형 컴포넌트 (0) | 2021.08.02 |
React. 이벤트 (0) | 2021.02.18 |
React. 컴포넌트 만들기, Props, state (0) | 2021.02.18 |
React. 리액트 입문 (1) | 2021.02.17 |