https://www.youtube.com/watch?v=nwwJ2xU7E8w&list=PLuHgQVnccGMCRv6f8H9K5Xwsdyg4sFSdi&index=28
1. Create
1. CRUD별 state.mode 값을 변경하기
1) 일단 CUD목록을 만들자
import React, {Component} from 'react';
import './App.css';
import Subject from "./component/Subject"
import TOC from "./component/TOC"
import Content from "./component/Content"
class App extends Component{
constructor(props){
super(props);
this.state={
mode :"read",
welcome : {title:'welcome', desc:'hello react'},
selected_content_id : 1,
subject:{title:'WEB', sub:'world wide web !'},
content:[
{id:1, title:"HTML", desc:"HTML is HyperText "},
{id:2, title:"CSS", desc:"Css is for design "},
{id:3, title:"JS", desc:"javascript is for intrective "}
]
}
}
render(){
console.log('APP render & this is : ' , this);
var _title, _desc = null;
if(this.state.mode === 'welcome'){
_title=this.state.welcome.title;
_desc=this.state.welcome.desc;
}else if(this.state.mode === 'read'){
var i =0;
while(i<this.state.content.length){
var data = this.state.content[i];
if(data.id === this.state.selected_content_id){
_title=data.title;
_desc=data.desc;
break;
}
i++;
}
}
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 data={this.state.content}
onChangePage={function(id){
this.setState({
mode : 'read',
selected_content_id : Number(id)
})
}.bind(this)}
></TOC>
<ul>
<li><a href="/create" >create</a></li>
<li><a href="/update" >update</a></li>
<li><input type="button" value="delete"></input></li>
</ul>
<Content title={_title} desc={_desc}></Content>
</div>
);
}
}
export default App;
2) CUD 목록을 컴포넌트로 변경
(1) Control.js
import React, {Component} from 'react';
class Control extends Component{
render(){
console.log('control render');
return(
<ul>
<li><a href="/create" >create</a></li>
<li><a href="/update" >update</a></li>
<li><input type="button" value="delete"></input></li>
</ul>
);
}
}
export default Control;
(2) app.js
- 맨위에
import Control from "./component/Control"
- <ul>...</ul> 있던 자리에 아래 코드 추가
<Control></Control>
3) 클릭할 때마다 모드변경
앞서 실습한 TOC 또는 WRB 클릭 시 mode를 변경했던 방법과 동일하게 진해하면 되는거 같다
* 깜박해서 삽질한 기억 : 양쪽 모두 .bind(this) 해줘야 한다는거~ ㅋ
app.js - 의 <Control> </Control> 부분에 사용자정의 이벤트 설정하고
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode
})
}.bind(this)}></Control>
control.js - 여기서 앞에 설정한 이벤트 가져가 쓰고
import React, {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;
4) 새로운 컴포넌트 생성 및 조정
(1) 기존의 <Content> 영역이, mode가 read일 때와 create 일때를 구분하여 출력되도록 코드 조정
- <Content> </Content> 자리를
{_content}로 바꾸고
- render(){ ...여기... return(); }
//'여기'에, {_content}에 대한 조건문(만약 모드가 create 라면~) 추가
(앞략)
render(){
console.log('APP render & this is : ' , this);
var _title, _desc,_content = null;
if(this.state.mode === 'welcome'){
_title=this.state.welcome.title;
_desc=this.state.welcome.desc;
_content = <Read_Content title={_title} desc={_desc}></Read_Content>
}else if(this.state.mode === 'read'){
var i =0;
while(i<this.state.content.length){
var data = this.state.content[i];
if(data.id === this.state.selected_content_id){
_title=data.title;
_desc=data.desc;
break;
}
i++;
}
_content = <Read_Content title={_title} desc={_desc}></Read_Content>
}else if(this.state.mode === 'create'){
_content = <Create_Content></Create_Content>
}
return ( ... 중략 ...);
}
(말략 ㅋ)
- Create_Content.js - '폼 태그' 추가, 'submit 클릭시 얼럿 테스트'까지 한.
참고로 onSubmit는 순수 html 스펙, 그 안에{function(){}} 내용은 리액트 스펙
import React, {Component} from 'react';
class Create_Content extends Component{
render(){
console.log('Create 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"></input></p>
<p><textarea name="desc" placeholder="description"></textarea></p>
<p><input type="submit"></input></p>
</form>
</article>
);
}
}
export default Create_Content;
e.preventDefault(); 했으니까, 얼럿창의 '확인' 버튼을 눌러고 페이지가 리로드되지 않고 얌전히 있으면 성공.
(2) 이젠, submit 하면, create 된 내용을 TOC 목록에 추가 ~
e.targrt이 form 자체를 가르킨다
- 얼럿 코드 아래 debugger; 를 작성하고 새로고침해서 e.targrt의 상세 속성을 확인해볼 수 있다.
- 일단 값 던지기
app.js
앞서 만든<Create_Content></Create_Content> 컴포넌트 안에 사용자정의 이벤트 onSubmit={}을 추가해 값을 받을 준비를 한다.
_content = <Create_Content onSubmit={function(_title, _desc){
console.log(_title, _desc)
}.bind(this)}></Create_Content>
Create_Content.js
form 태그 안에 있는 값들을 사용자정의 이벤트 onSubmit(제목, 내용)의 인자로 담아 app.js로 전달한다.
//debugger;
this.props.onSubmit(e.target.title.value, e.target.desc.value);
- 이번엔 UI 목록에 추가
app.js
(---초략)
//*** 여긴 constructor(props){ ...여기(바로뒤에); this.state={..} }
//1) contents의 수를 담은 변수를 추가하기(ui와 상관없으니, state 밖에 선언)
this.count_contents_id=3;
(---중략)
//*** 여긴 <Create_Content onSubmit={function(){ ...여기~... }}>
//1) contents 맨뒤에 넣기 위해 +1
this.count_contents_id=this.count_contents_id+1;
//2) 추가하기 - 아직 리액트는 모른다.
this.state.content.push({
id:this.count_contents_id, title:_title, desc:_desc
});
//3) 이제 리액트도 안다.
this.setState({
content: this.state.content
});
(---말략)
- 하지만, 다시. app.js
다른 방식의 create - push VS concat
- state에 값을 변경하는 경우 원본을 변경하지 않고 새로운 데이터를 넣는 concat를 추천한다
- 추후 성능개선 이슈 등에 더 유리하다 고 한다.
import React, {Component} from 'react';
import './App.css';
import Subject from "./component/Subject"
import TOC from "./component/TOC"
import Control from "./component/Control"
import Read_Content from "./component/Read_Content"
import Create_Content from "./component/Create_Content"
class App extends Component{
constructor(props){
super(props);
this.count_contents_id=3;
this.state={
mode :"create",
welcome : {title:'welcome', desc:'hello react'},
selected_content_id : 1,
subject:{title:'WEB', sub:'world wide web !'},
content:[
{id:1, title:"HTML", desc:"HTML is HyperText "},
{id:2, title:"CSS", desc:"Css is for design "},
{id:3, title:"JS", desc:"javascript is for intrective "}
]
}
}
render(){
console.log('APP render & this is : ' , this);
var _title, _desc,_content = null;
if(this.state.mode === 'welcome'){
_title=this.state.welcome.title;
_desc=this.state.welcome.desc;
_content = <Read_Content title={_title} desc={_desc}></Read_Content>
}else if(this.state.mode === 'read'){
var i =0;
while(i<this.state.content.length){
var data = this.state.content[i];
if(data.id === this.state.selected_content_id){
_title=data.title;
_desc=data.desc;
break;
}
i++;
}
_content = <Read_Content title={_title} desc={_desc}></Read_Content>
}else if(this.state.mode === 'create'){
_content = <Create_Content onSubmit={function(_title, _desc){
//1
this.count_contents_id=this.count_contents_id+1;
//2-1
// this.state.content.push({
// id:this.count_contents_id, title:_title, desc:_desc
// });
// this.setState({
// content: this.state.content
// });
//2-2
var _new_content = this.state.content.concat({
id:this.count_contents_id, title:_title, desc:_desc
});
this.setState({
content: _new_content
});
}.bind(this)}></Create_Content>
}
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 data={this.state.content}
onChangePage={function(id){
this.setState({
mode : 'read',
selected_content_id : Number(id)
})
}.bind(this)}
></TOC>
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode
})
}.bind(this)}></Control>
{_content}
</div>
);
}
}
export default App;
결과는 위와 동일~
1+a.
1) push VS concat
(1) 원본을 바로 수정하지 않고, 복제본을 만들어서 수정한다.
(2) push는 shouldComponentUpdate를 사용 할 수 없다.
2) shouldComponentUpdate(newPros, newState)
(1) TOC가 화면에 표시되기 위해서는 this.state.content[]이 반영되는데
- content[]의 내용이 바뀌지 않았을 때는 content[]의 render()가 실행될 필요가 없지만 계속 실행되고 있다.
(2) shouldComponentUpdate(){ return ...} 를 추가하면
- render()보다 먼저 실행된다.
- return 이 true 이면 모든 render()를 실행하고, false이면 render()를 실행하지 않는다.
- shouldComponentUpdate는 새롭게 바뀐 값과 이전 값에 각각 접근할 수 있다.
- 새롭게 바뀐 값과 이전 값에 맞춰 render()의 실행여부를 개발자가 조절할 수 있다.
TOC.js
import React, {Component} from 'react';
class TOC extends Component{
shouldComponentUpdate(newProps, newState){
console.log(" ======> shouldComponentUpdate",
newProps.data,
this.props.data
);
if(this.props.data === newProps.data){
return false;
}
return true;
}
render(){
console.log(' => TOC render');
var lists=[];
var data = this.props.data;
var i=0;
while(i<data.length){
lists.push(<li key={data[i].id}>
<a href={"/content/"+data[i].id}
data-skdjfnsdkfj = {data[i].id}
onClick={function(id,e){
e.preventDefault();
this.props.onChangePage(id);
}.bind(this, data[i].id)}
> {data[i].title}
</a> </li>);
i = i+1;
}
return(
<nav>
<ul>
{lists}
</ul>
</nav>
);
}
}
export default TOC;
2) immutable 불변성
(1) Array의 특징 응용
불변성에 대한 부분만 고려된다면, shouldComponentUpdate() 없이 push로도 구현할 수 있다.
//2-1 + immutable 불변성
var _new_content = Array.from(this.state.content);
_new_content.push({
id:this.count_contents_id, title:_title, desc:_desc
});
this.setState({
content: _new_content
});
(2) 객체의 경우,
but, 혹시나 해서 테스트해봒는데... ㅋ
(3) 이렇게 왔다갔다하기 애매한 경우 -> 라이브러리를 활용할 수도 있음!
모든 명령어들이~ 다~ 원본에 대해 불변하게 되기 때문에 혼란을 줄여줄 수 있다.
https://github.com/immutable-js/immutable-js
2. Update
https://www.youtube.com/watch?v=YKdebEty6uQ&list=PLuHgQVnccGMCRv6f8H9K5Xwsdyg4sFSdi&index=36
(ing)
'새로워지기 > 서른의 생활코딩' 카테고리의 다른 글
[생활코딩따라가기] 예고 목차 (0) | 2019.06.01 |
---|---|
[생활코딩따라가기] React CRUD 중 UD ~ go~ (0) | 2019.05.29 |
[생활코딩 따라가기] React 16 event 풀~패키지 챕터 (0) | 2019.05.27 |
[생활코딩 따라가기] React 15 props와 state (0) | 2019.05.26 |
[생활코딩 따라가기] React 12~14 deep dive컴포넌트 (0) | 2019.05.26 |
댓글