이번에는 bind 와 setState를 설명하기 전에 짜고있는 코드를 한번 쭉 복기하고 bind와 setState를 설명해보겠다.
class App extends Component {
constructor(props){
super(props);
this.state = {
mode:'read',
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 informatrion'},
{id:2, title:'CSS', desc:'CSS is design.'},
{id:3, title:'JS', desc:'JS is for interactive'}
]
}
}
가장 부모의 Component인 클래스 App에 state값을 설정하는 모습이다. state값에는
mode값이 변경됨에 따라 content의 내용이 변경되는 mode값이고
selected_content_id(2는 값은 그냥해놓은값)값은 TOC(HTML,CSS,JS 하이퍼링크가 부여된 코드)가 클릭되는 이벤트의 따라 state의 contents에 부여해놓은 id값이 변경되는데 그에 맞는content의 내용이 표시되게끔 설정해둔 값이다.
welcome은 mode값이 welcome으로 변경될 때 content의 표시될 title과 sub를 나타낸것이다.
render() {
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.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;
}
}
어떤 html을 그릴것인가 정의하는 render함수, 그곳엔 mode값이 변경될때마다 들어갈 _title, _desc를 아직 정해지지않은 null값으로 정의해두고 if(this.state.mode) 즉 mode값이 어떤 값일 때 그곳에 _title과 _desc에 어떤값을 부여할 것이다. 라는 규칙이다.
mode값이 read값이 될때는 while문과 if문이 중첩되는데 while문은 contents의 길이만큼 반복될 것인데 반복될 동안 contents를 data라는 변수에 담아 data.id와 selcected_content_id가 일치할경우 _title,_desc에 값을 부여하고 break를 걸어 빠져나오게한다.
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>
<Content title={_title} desc={_desc}></Content>
</div>
);
}
}
여기서는 다른부분은 간단한내용이라 onChangePage와 setState, bind(this)에 대해서만 얘기하겠다.
우선 Subject안에 헤더(또는 타이틀, 로고 등)를 클릭했을 때 mode의 값이 welcome으로 바뀌는 setState를 onChangePage로 정의했다.
Subject내용은 다음의 Component를 보겠다.
class Subject extends Component{
render(){
return (
<header>
<h1><a href="/" onClick={function(e){
e.preventDefault();
this.props.onChangePage();
}.bind(this)}>{this.props.title}</a></h1>
{this.props.sub}
</header>
);
}
}
즉 Web이라는 h1태그의 a태그를 onClick했을 때 실행되는 함수에 앞서 정의해놓은 onChangePage를 실행하라 라고 작성한것이 onClick={} 안에 모두 들어있다.
앞서 return되는 값들의 코드중 대부분의 this는 상위의 Component인 App을 가르키고,
function(id){
this.setState({
mode:'read',
selected_content_id : Number(id)
});
}.bind(this)
this.setState의 this는 그 상위인 function을 뜻한다. 여기서 만약 .bind(this)만 제거하면 어떤 에러가 날까 ?
Web이라는 타이틀을 클릭했을 때
TypeError: this.setState is not a function 에러가 나는것을 볼수있다.
this.setState({})로 함수작성을 했는데 함수로 인식을 못한다는 내용같다. 이때 위의 코드와같이 bind(this)를 추가해준다면 왜 정상실행이 될까? 로 나는 bind와 setState를 유추했다.
bind는 묶는다는 뜻인데 즉 bind(this) = 묶는함수(App)
아직 머리속에서 완벽히 이해를 못해 정리가 안됬다. 다된다면 수정하겠다!