20.1강 update 구현
else if (this.state.mode === 'update') {
var _content = this.getReadContent();
_article = <UpdateContent data={_content} onSubmit={function (_title, _desc) {
this.max_content_id = this.max_content_id + 1;
var _contents = this.state.contents.concat(
{ id: this.max_content_id, title: _title, desc: _desc }
)
this.setState({
contents: _contents
});
console.log(_title, _desc)
}.bind(this)}></UpdateContent>
}
여기서 mode === 'Update' 라고 적어서 계속 진행이 안되었다....
업데이트 기능은 read 기능과 create 기능이 결합되어 있는 것
update 할려면 create 처럼 폼이 었어야하고 기존의 컨텐츠를 수정 하는 것이기 때문에
read 처럼 기존의 컨텐츠를 불러와서 form에다가 내용을 추가해주는 작업이다.
너무 복잡해서 새로운 함수로 쪼개서 분리시키기 + UpdateContent 라고 하는 컴퍼넌트가 실행될 때, 입력 값으로 현재 선택된 콘텐트의 id가 2번인데, 애를 UpdateContent 이 컴퍼넌트에 주입시켜주는 작업을 해보자.
selected_Content_id와 같은 원소를 찾아줘야한다. getReadContent(){ } 사용
getReadContent(){ // 깔끔하게 만들기
var i = 0;
while (i < this.state.contents.length) {
var data = this.state.contents[i];
if (data.id === this.state.selected_content_id) {
return data;
break;
}
i = i + 1;
}
}
getContent() {
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 _content = this.getReadContent();
_article = <ReadContent title={_content.title} desc={_content.desc}></ReadContent>
} else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function (_title, _desc) {
// add content to this.state.contents
this.max_content_id = this.max_content_id + 1;
// this.state.contents.push(
// {id:this.max_content_id, title:_title, desc:_desc}
// );
var _contents = this.state.contents.concat(
{ id: this.max_content_id, title: _title, desc: _desc }
)
// var newContents = Array.from(this.state.contents);
// newContents.push({id:this.max_content_id, title:_title, desc:_desc}
// )
// this.setState({
// contents:newContents
// });
this.setState({
contents: _contents
});
console.log(_title, _desc)
}.bind(this)}></CreateContent>
} else if (this.state.mode === 'update') {
var _content = this.getReadContent();
_article = <UpdateContent data={_content} onSubmit={function (_title, _desc) {
this.max_content_id = this.max_content_id + 1;
var _contents = this.state.contents.concat(
{ id: this.max_content_id, title: _title, desc: _desc }
)
this.setState({
contents: _contents
});
console.log(_title, _desc)
}.bind(this)}></UpdateContent>
}
return _article;
}
render() {
console.log('App render');
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>
{this.getContent()} // 요부분
</div>
);
}
}
20.2강 update 구현 : form
컴퍼넌트로 주입된 데이터를 기반으로 해서 이 컴퍼넌트에 기본적으로 입력되는 값 셋팅
forms 제어와 관련되어있다.
state화
constructor(props){
super(props);
this.state = {
title:thos.props.date.title
}
)
inputFormHandler를 사용해서 this.setState, bind(this) 중복제거
UpdateContent.js
import React, {Component} from 'react';
class UpdateContent extends Component {
constructor(props){
super(props);
this.state = { // props는 readonly이므로 가변적으로 만들기 위해 state화
title:this.props.data.title,
desc:this.props.data.desc
}
// inputFormHandler 함수 뒤에 붙는 .bind(this)가 중복되므로 미리 설정하여 제거
this.inputFormHandler = this.inputFormHandler.bind(this);
}
inputFormHandler(e){
// e.target.name으로 이벤트 객체의 name 값인 title / desc 값 가져옴
this.setState({[e.target.name]:e.target.value});
}
render(){
return(
<article>
<h2>Update</h2>
<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"
value={this.state.title}
onChange={this.inputFormHandler} // state를 변경하기 위해 필요
></input></p>
<p>
<textarea onChange={this.inputFormHandler}
name="desc"
placeholder="description"
value={this.state.desc}></textarea>
{/* html과 다르게 value로 기본값 설정 */}
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
)
}
}
export default UpdateContent;
20.3강 update 구현 : state 변경
저번강의에서는 props로 들어온 데이터를 state로 만들고 이 state에 값을 각각의 form과 동기화 시켜서 state값을
계속해서 변화시키는 방법을 살펴보았다.
하지만 update를 하려면 어디를 update 할 것인지에 대한 식별자가 필요하다.
보통 form에서는 id와 같이 수정할 때, id는 사용자한테 보일 필요가 없기 때문에 히든 form을 쓴다.
존재하지만 눈에 보이지않는 친구. 그럼에도 할 필요가있나?
'JS가 동작하지 않을 때도 여기 있는 코드가 동작하게 한다'가 JS로 우리가 뭔가 만들 때 기본적인 기조이고
다른 용도로 활용될 가능성이 있기 때문에 JS없이도 구현에 충실하는 것이 좋다.
#기존
onSubmit 버튼을 눌렀을 때, onSubmit 이벤트가 발생 -> 이 컴퍼넌트로 들어온 this.props.onSubmit을
실행할 때 e.target.title.value, e.target.desc.value 이런식으로 한다.
여기다가 id값까지 주면 금상첨화 => state.id, title, desc 로 바꾸기
<form action="/create_process" method="post"
onSubmit={function (e) {
e.preventDefault();
this.props.onSubmit(
this.state.id,
this.state.title,
this.state.desc
);
}.bind(this)}
>
<input type="hidden" name="id" value={this.state.id}></input>
this.max_content_id 는 create 할 때 필요한 것이니 Update 쪽에서는 지워준다.
concat은 기존에 있던 데이터를 추가할 때 쓰는 것인데 우리는 지금 수정을 하려고 하니까 복제를 할 것이다.(불변하는, 원본을 바꾸지 않지만 값은 같은 컨텐츠 만들기. 나중에 성능을 튜닝할 때 필요하다)
우리가 수정하려고 하는 배열이나 객체를 수정하려고 할 때는 개를 복제한다. 그리고 복제한 것을 push해서 값을 추가한다. push를 concat한 것.
이렇게 하고 update하면 잘 작동하지만 보통 우리가 알고있는 방식은 그 바뀐 것으로, 상세보기 까지 되는 것. 고로 mode: "update"를 -> "read"로 바꿔주면 된다. selected_conent_id를 방금 우리가 추가한 값 this.max_content_id
로 바꿔준다.
Array.from(this.state.contents); 사용
-> 원본을 복사한 새로운 배열이 만들어진다. 이것을 var _contents라는 이름으로 바꾸기
_contents 안에 있는 원소들 하나하나를 뒤져서 id값이 우리가 수정하고자 하는 것과 같은 원소를 찾아야한다.
else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function (_title, _desc) {
this.max_content_id = this.max_content_id + 1;
var _contents = Array.from(this.state.contents);
_contents.push({id:this.max_content_id, title:_title, desc:_desc});
this.setState({
contents: _contents,
mode:'read',
selected_content_id:this.max_content_id
});
}.bind(this)}></CreateContent>
} else if (this.state.mode === 'update') {
_content = this.getReadContent();
_article = <UpdateContent data={_content} onSubmit={
function (_id, _title, _desc) {
var _contents = Array.from(this.state.contents);
var i = 0;
while(i < _contents.length){
if(_contents[i].id === _id){
_contents[i] = {id:_id, title:_title, desc:_desc};
break;
}
i = i + 1;
}
this.setState({
contents: _contents,
mode:'read'
});
}.bind(this)}></UpdateContent>
}
return _article;
}
while을 써야 list들을 눌렀을 때 값이 뜬다.
i를 1씩 증가시킨다. 만약에 _contents[i]와 우리가 지금 입력받은 id 값이 같다면 우리는 그 객체를 교체해줘야한다.
{id:_id, ....desc:_desc} 이런식으로 한다. 그리고 이걸 했으면 조건 반복문을 할 필요가 없으니까 break를 해주는 것이다.
var i = 0;
while(i < _contents.length){
if(_contents[i].id === _id){
_contents[i] = {id:_id, title:_title, desc:_desc};
break;
}
i = i + 1;
}
this.setState({
contents: _contents
이제 list에 있는 HTML, CSS, JS를 클릭하고 누르면 잘 바뀌고 수정이 가능하다. Update가 제일 힘들다. read, create를 다 할 줄 알아야하기 때문이다.
21강 delete 구현
class App extends Component {
constructor(props) {
super(props);
this.max_content_id = 3;
this.state = {
mode: 'welcome',
selected_content_id: 2,
subject: { title: 'WEB', sub: 'World Wid 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' }
]
}
}
여기서 mode는 맨 처음 로딩화면을 어디로 할 지 맞춰주는 부분. create였던 것을 welcome으로 바꾸기.
Contorl 안에 delete버튼이 있다. 이 버튼은 onChangeMode라고 하는 props를 호출하고 있다.
<li><input onClick={function(e){
e.preventDefault();
this.props.onChangeMode('delete');
}.bind(this)} type="button" value="delete"></input></li>
</ul>
);
}
}
그러면 onChangeMode의 function (_mode)라는 값이 delete 로써 호출된다면 삭제 operation 시작된 것.
만약에 _mode가 delete 이면 삭제를 해주고 그렇지 않다면 welcome으로 페이지 전환만 해줘라.
삭제가 시작됐을 때 어떤일이 일어나야 좋을까?
제일 먼저 어떤 일이 일어나야 할까를 알려주면 좋을 것 => confirm 사용
confirm은 앞에 window.를 붙여줘야만 쓸수가 있다.
confirm을 실행 했을 때 사용자가 확인을 누르면 true, 캔슬을 누르면 false가 실행된다.
여기서 우리가 해야할 것은?
누구를 삭제할 것인가? selcted_content_id 를 통해 알 수 있다.
2번째로 어떤 데이터를 삭제할 것인가는 contents 쪽에서 찾아낼 수 있다.
while을 사용해서 찾아라.
this.state.contents는 나중에 setState로 들어갈 것이다. 고로 복제를 하면 더욱 좋다 => Array.from 사용
_contents[i].id === this.state.selected_content_id와 같다면?
_contents에서 어디서부터 어디까지를 지울 것인가 - > splice를 사용하면 된다.
우리가 발견한 원소의 id값부터 한개를 지우겠다 하면 _contents의 원본을 바꾼다.
그 값을 바꿨으면 break를 때려주면 된다. 그 후 setState로 contents의 값으로 _content를 넣는다.
삭제가 잘 됐다면 mode를 welcome으로 바꿔준다. 보여줄게 없으니까!
confirm() 안에다가 'really'를 써주면 경고창 문구가 뜰 것이다. state도 없어졌고 welcome으로 이동했고
alert를 추가해서 삭제가 잘 되었다고 뜨는 문구도 추가해주면 완벽.
<Control onChangeMode={function (_mode) {
if(_mode === 'delete'){
if(window.confirm('really?')){
var _contents = Array.from(this.state.contents);
var i = 0;
while(i < this.state.contents.length){
if(_contents[i].id === this.state.selected_content_id){
_contents.splice(i,1);
break;
}
i = i + 1;
}
this.setState({
mode:'welcome',
contents:_contents
})
alert('deleted');
}
} else{
this.setState({
mode: _mode
});
}
}.bind(this)}></Control>
# Delete를 한 경우 selected_content_id는 삭제된 객체의 id를 가리키고 있기 때문에 바로 Update를 누르게 되면 Uncaught TypeError: Cannot read property 'id' of undefined 에러가 발생하게 됩니다. 그래서 Control의 setState에서 selected_content_id의 값을 수정할 필요가 있을 것 같습니다.
#그런데 제가 수업을 들으면서 코드를 조금 변경해서 delete 후에 새로 create 시에는 error가 발생되더군요. 아마 delete 후 "this.max_conetent_id--"를 해줘야 할 거 같습니다. (저같은 경우 filter를 쓴 경우이긴한데 다른 분들도 에러가 나지 않을까 싶네요) 강의해주신 React CRUD 예제만 이해했다면 React를 사용해서 웬만한 웹사이트는 다 구성할 수 있을 것 같네요. 다시 한 번 감사드립니다! 이제 React class vs function style, react router 정주행하러 갑니다.
22강 수업을 마치며
immutable
- 불변성
- immutable-js
- 배열과 객체의 대체재- 모든 연산이 원본이 복제된 결과 리턴
router
- 페이지 전환을 할 때마다 네트워크 로딩을 하지 않는 장점이 있지만, url로 페이지를 찾아올 수 없다는 단점
- react router - url에 따라 컴포넌트가 실행될 수 있도록 도와줌
create-react-app
- npm run eject
- 감춰진 create-react-app의 설정을 수정할 수 있음- 되돌릴 수 없으므로 주의
redux
- 기존 react에서는 자식 컴포넌트 / 부모 컴포넌트 사이에 props나 이벤트 버블링 필요
- redux는 중앙 데이터 저장소에 모든 컴포넌트가 연결되어 있고, 저장소의 내용이 변경되면 관련된 컴포넌트가 변경됨
react server side rendering
- 서버에서 웹페이지를 완성한 후 클라이언트에 전송하는 방식으로 애플리케이션 구동
- 초기 구동시간 단축- JavaScript 특유의 로딩이 필요없는 특성 유지
- 검색 엔진 등의 로봇이 html을 읽도록 할 수 있음
react native
- react 방식으로 네이티브 앱 제작 가능
- 하나의 코드가 거의 모든 애플리케이션에서 동작 가능'
#댓글
- React Router: URL마다 적당한 컴포넌트를 뿌려줌
- Redux: 모든 컴포넌트가 공통적으로 쓰는 저장소를 만들어서, 어느 컴포넌트에서도 손쉽게 state를 바꿀 수 있게 해줌 (순수 React로는 상위에서 하위 컴포넌트를 손볼때는 props로 쉽게 가능하지만, 하위에서 상위 state를 바꿀려면 props값으로 function을 넣어야 함)
- React Native: React와 같은 방법으로 네이티브앱 (iOS, android)을 쉽게 만들 수 있게 해줌
'[자기계발] > 유튜브로 코딩배우기' 카테고리의 다른 글
[생활코딩] JavaScript 문법 - 조건문 (0) | 2021.05.20 |
---|---|
[생활코딩] JavaScript 기본문법 정리 (숫자와 문자, 변수, 주석, 줄바꿈과 여백, 비교) (0) | 2021.05.18 |
[생활코딩]React 강의-4 18강~19강 create (0) | 2021.05.10 |
[생활코딩]React 강의-3 17강 Component 이벤트 만들기 (0) | 2021.05.08 |
CS 전공을 해야할까? 개발자가 되기 위해 대학을 나와야할까? (0) | 2021.04.21 |