props
와 state
의 차이점?props
는 부모 컴포넌트로부터 읽을 수만 있는 것이고, 웹 사이트의 사용자가 수정할 수 없다.
반면 state
는 웹 사이트와 사용자간의 상호작용을 통해 수정될 수 있는, 일종의 '버튼'이다. this.setState
를 통해 상태를 변경할 수 있다.
하지만 공통점은, 두 개 모두 상태가 변경되면
render()
함수가 재호출된다는 것이다.
사진처럼 컴포넌트들이 위아래로 연결되어 있을 때,
상위 컴포넌트에서 하위 컴포넌트에게 명령을 할 때(값을 전달할 때)는 props
를 통해서 전달하고,
하위 컴포넌트에서 상위 컴포넌트에게 명령을 할 때는 event를 통해서, 즉 state
를 변경함으로서 수행한다.
(사진에서 의미하는 것은 Redux
를 사용하면 이러한 변경 과정이 하나하나의 컴포넌트를 모두 거치지 않고 한 번에 가능하게 할 수 있다는 것이다.)
지금까지 만들어놓았던 것에서, 'create', 'update', 그리고 'delete' 기능을 추가해볼 것이다.
props
, state
, 그리고 event를 활용한다.
< 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 onClick={function(e) {
e.preventDefault();
this.props.onChangeMode('delete');
}.bind(this)} type="button" value="delete"></input></li>
</ul>
)
}
}
export default Control;
위와 같이 'create', 'update', 'delete' 기능을 구현하는 Control.js
파일을 새로 만들어준다.(원래 만들어놨던 컴포넌트 파일의 양식을 복사해서 그대로 사용하면 편리하다.)
'create'과 'update'는 a 태그로 만들고 전에 했던 것과 유사하게 e.preventDefualt()
, this.props.onChangeMode('create')
를 넣어준다. 클릭이 되었을 때, 상태 변경을 멈추고 'create'로 mode를 변경하라는 의미이다.
'delete'도 동일하게 작성하지만 button으로 생성해준다.(이유가 뭐라고 했더라...)
< App.js >
...
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode
});
}.bind(this)}></Control>
...
메인 파일이 되는 App.js에는 <Control>
태그를 사용한 코드를 추가해준다.
'_mode'라는 상태를 나타내는 새로운 변수를 만들고, this.setsState()
함수를 통해 state
가 변경될 수 있도록 해준다.
함수 끝에 .bind(this)
를 붙여주는 것을 잊지 말자!
여기까지 하면 'mode' 변수가 클릭할 때마다 상태가 바뀌는 것을 볼 수 있다.
본격적으로 'create', 'update', 'delete' 기능을 구현해보자.
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(){
this.setState({mode:'read'});
}.bind(this)}
data={this.state.contents}></TOC>
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode
});
}.bind(this)}></Control>
{_article}
</div>
);
화면에서 맨 밑에 들어갈 문구를 _article
이라는 변수를 새로 만들어 대치해준다. 누르는 버튼에 따라 유동적으로 바뀌게 하기 위함이다.
...
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++;
}
_article = <ReadContent title={_title} desc={_desc}></ReadContent>
}
else if(this.state.mode === 'create'){
_article = <CreateContent></CreateContent>;
}
...
그에 따라 렌더부의 윗부분도 _article
로 알맞게 수정해준다.
mode의 상태에 따라 _article
에 할당되는 값을 다르게 하여, 유동적으로 다른 글들이 출력될 수 있도록 하는 것이다.
그리고 'create' 버튼을 누를 때 출력되게 할 태그를 구현한 CreateContent.js
파일도 새로 만들어 적용해준다.
그러면 이렇게 mode에 따라 출력이 전환되는 것을 볼 수 있다.
이전 차시에 추가하여 'form 태그'를 이용해 입력 칸을 만들어보자.
다음은 form 태그에 대한 설명이다.
ChatGPT
"<form>
태그는 HTML에서 사용되는 요소로, 웹 페이지에서 사용자로부터 데이터를 수집하거나 제출하는 데 사용됩니다. 주로 사용자 입력을 받는 부분을 감싸는 데 사용되며, 이를 통해 데이터를 서버로 전송하거나 클라이언트 측에서 처리할 수 있습니다.
폼 안에는 다양한 입력 요소가 포함될 수 있으며, 이러한 입력 요소는 사용자로부터 데이터를 수집하는 데 사용됩니다. 예를 들어<input>
,<textarea>
,<select>
,<button>
등이 폼 요소로 사용될 수 있습니다. "
< CreateContent.js >
...
<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>
...
'CreateContent.js'파일에 위의 코드를 추가해준다. 3개의 form 태그를 사용한 것이다.
*
<input>
태그와<textarea>
태그의 차이?
: < input >은 주로 짧은 텍스트 입력 또는 특정 형식의 입력(이메일, 비밀번호 등)을 받을 때 사용되며, < textarea> 는 여러 줄의 긴 텍스트 입력을 받을 때 사용됩니다. 주로 긴 텍스트 설명이나 사용자가 긴 글을 입력해야 하는 경우 사용됩니다.
'placeholder'은 입력 칸에 아무것도 입력되지 않았을 때 뜨는 기본 문구를 나타낸다.
3개의 form 태그 중 주목해야 할 것은 마지막 <input type='submit'>
부분이다.
타입을 'submit'으로 지정하면 react 고유의 기능이 발동되어, 사진처럼 '제출'이라고 쓰인 버튼이 생성되고 onSubmit
함수가 호출된다.
그렇기에 위의 코드에서 onSubmit
이 호출되었을 때 어떤 작업을 수행할지 작성해준 것이다.
하지만 이 함수가 호출되면, 프로그램은 자동으로 페이지를 새로고침하려고 하기 때문에 우리는 또다시 e.preventDefault()
로 새로고침을 방지해야 한다.
이후에는 알림창을 띄우도록 코드를 작성했다.
이렇게 새로고침없이 잘 작동이 되는 것을 볼 수 있다.
.push
처럼 오리지널 데이터를 건드리는 것 쓰지 않고, .concat
처럼 새로운 데이터를 만드는 것 사용하기!
.concat
를 써야하는 이유! 수정 시에 원본의 '복제본'을 수정하는 것이 안전하다.
shouldComponentUpdate(){
return false;
}
를 하면 항상 render()
가 실행되지 않는다! 항상 'false'를 return하기 때문이다.
이걸 이용해서 props가 바뀌었을 때만 render()
가 호출되도록 효율적으로 작동하게 할 수 있다.
< TOC.js >
class Toc extends Component {
shouldComponentUpdate(newProps, nesState){
console.log('===> TOC render shouldComponentUpdate',
newProps.data
,this.props.data);
if(this.props.data === newProps.data){
return false;
}
return true;
}
render() {
...}
이렇게, if(this.props.data === newProps.data)
의 조건문을 통해 props가 바뀌었을 때만 밑의 render()
함수가 실행되도록 할 수 있다. 하지만 이렇게 해서 성능의 향상 효과가 미미하다면 그냥 하지 않아도 무방하다.
원본의 교체?