https://www.youtube.com/watch?v=nwwJ2xU7E8w&list=PLuHgQVnccGMCRv6f8H9K5Xwsdyg4sFSdi&index=28
1. Create
1. Change the state.mode value for each CRUD action
1) First, let's make the CUD list
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) Extract the CUD list into a component
(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
- At the top
import Control from "./component/Control"
- In the spot where <ul>...</ul> was, add the code below
<Control></Control>
3) Change the mode on every click
It looks like you can go about it the same way as the earlier practice that changed the mode when clicking TOC or WRB.
* A bump I forgot about: you have to do .bind(this) on both sides, heh
app.js - set a custom event on the <Control> </Control> section and
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode
})
}.bind(this)}></Control>
control.js - here, bring in that event we set up and use it
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) Create a new component and adjust things
(1) Adjust the existing <Content> block so it renders differently when mode is 'read' vs 'create'
- The <Content> </Content> spot
becomes {_content}
- render(){ ...here... return(); }
// In 'here', add a conditional for {_content} (if mode is create then~)
(앞략)
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 — added the 'form tag' and tested an alert on submit.
For reference, onSubmit is the plain HTML spec, and the {function(){}} inside it is the React spec.
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;
Since we called e.preventDefault();, if you click 'OK' on the alert and the page doesn't reload and just sits there quietly, it worked.
(2) Now, on submit, add the created item to the TOC list ~
e.target points to the form itself
- Write 'debugger;' below the alert line and refresh, and you can inspect the detailed properties of e.target.
- First, pass the values up
app.js
On the <Create_Content></Create_Content> component we just created, add a custom event onSubmit={} to prepare to receive the values.
_content = <Create_Content onSubmit={function(_title, _desc){
console.log(_title, _desc)
}.bind(this)}></Create_Content>
Create_Content.js
Take the values from inside the form tag, pack them as arguments into the custom event onSubmit(title, desc), and hand them up to app.js.
//debugger;
this.props.onSubmit(e.target.title.value, e.target.desc.value);
- This time, add it to the UI list
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
});
(---말략)
- But, take two. app.js
A different way to create — push VS concat
- When mutating state, concat is recommended because it doesn't modify the original and returns new data instead.
- It's also said to be better for later performance-improvement issues.
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;
The result is the same as above~
1+a.
1) push VS concat
(1) Don't mutate the original directly, work on a copy.
(2) With push, shouldComponentUpdate cannot be used.
2) shouldComponentUpdate(newPros, newState)
(1) For TOC to render on screen, this.state.content[] gets reflected,
- but when the contents of content[] haven't changed, render() of content[] doesn't need to run, yet it keeps running.
(2) If you add shouldComponentUpdate(){ return ...}
- it runs before render().
- if the return is true, every render() runs; if false, render() doesn't run.
- shouldComponentUpdate can access both the newly changed value and the previous value.
- The developer can control whether render() runs based on the newly changed value and the previous value.
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 — immutability
(1) Leveraging features of Array
If only immutability is the concern, you can pull it off with push too, without shouldComponentUpdate().
//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) For objects,
but, I tested it just in case... heh
(3) When it gets too fuzzy to keep switching back and forth —> you can also lean on a library!
Every operation is immutable with respect to the original, which cuts down on confusion.
https://github.com/immutable-js/immutable-js
immutable-js/immutable-js
Immutable persistent data collections for Javascript which increase efficiency and simplicity. - immutable-js/immutable-js
github.com
2. Update
https://www.youtube.com/watch?v=YKdebEty6uQ&list=PLuHgQVnccGMCRv6f8H9K5Xwsdyg4sFSdi&index=36
(ing)


