예전 react에서는 컴포넌트에 쓸모없는 div로 감싸줘야지 실행이 됐던 문제가 있다. 이 div 때문에 쓸모없는 코드가 생기고 css의 적용에도 불편함이 있었다.
이제는 개션되어 빈 태그 <React.Fragment>를 이용해서 새로운 div 없이 사용할 수 있다. 또한 babel 툴을 이용하면 빈 태그 <>만 적어도 쓸모없는 div 사용을 없앨 수 있다.
e와 function은 this가 가리키는 대상이 다르기 때문에 사용에 주의를 해줘야한다.
setState는 변환하는 함수를 지정한다. 객체를 이용하지 않고 함수를 지정해서 매개변수를 통해서 값을 변경할 수도 있다.
가령 카운터를 만든다고 했을 때,
// 객체 방식으로 지정
this.setState({
value : this.state.value + 1;
});
this.setState({
value : this.state.value + 1;
});
this.setState({
value : this.state.value + 1;
});
value가 0에서 시작했을 때, 위와 같은 방식으로 value 값이 3이 되길 기대할 수 있지만, setState는 비동기방식이기 때문에 값에서 1이 도출될 수도 있다.
setState는 비동기임을 명심하자.
따라서 아래와 같이 함수형으로 setState를 지정해주면 원하는 결과를 얻을 수 있다.
this.setState((prevState) => {
return{
value = prevState.value + 1;
};
});
this.setState((prevState) => {
return{
value = prevState.value + 1;
};
});
this.setState((prevState) => {
return{
value = prevState.value + 1;
};
});
위의 내용을 적용한 구구단 코드는 아래와 같다
<body>
<div id="root"></div>
<script type="text/babel">
class GuGuDan extends React.Component{
state = {
first : Math.ceil(Math.random() * 9),
second : Math.ceil(Math.random() * 9),
value : '',
result : '',
answer : '',
};
onSubmit = (e)=>{
e.preventDefault();
if(parseInt(this.state.value) == this.state.first * this.state.second){
this.setState((prevValue) => {
return {
result : '정답' + prevValue.value,
first : Math.ceil(Math.random() * 9),
second : Math.ceil(Math.random() * 9),
value : '',
};
});
}
}
onChange = (e) =>{
this.setState({value : e.target.value });
}
render(){
return (
<React.Fragment>
<div>{this.state.first} 곱하기 {this.state.second}는?</div>
<form onSubmit= {this.onSubmit}>
<input type="number" value={this.state.value} onChange={this.onChange}/>
<button type="submit">입력</button>
</form>
<div>{this.state.answer}{this.state.result}</div>
</React.Fragment>
);
}
}
</script>
<script type="text/babel">
ReactDOM.createRoot(document.querySelector("#root")).render(<GuGuDan/>)
</script>
</body>
만약에 입력 이후 input에 focus를 주고 싶다고 생각해보자. 이 때는 ref(reference)를 이용해준다.
<body>
<div id="root"></div>
<script type="text/babel">
class GuGuDan extends React.Component{
state = {
first : Math.ceil(Math.random() * 9),
second : Math.ceil(Math.random() * 9),
value : '',
result : '',
answer : '',
};
onSubmit = (e)=>{
e.preventDefault();
if(parseInt(this.state.value) == this.state.first * this.state.second){
this.setState((prevValue) => {
return {
result : '정답' + prevValue.value,
first : Math.ceil(Math.random() * 9),
second : Math.ceil(Math.random() * 9),
value : '',
};
});
this.input.focus();
}else{
this.setState({
result : '땡',
value : '',
})
this.input.focus();
}
};
onChange = (e) =>{
this.setState({value : e.target.value });
};
input;
render(){
return (
<React.Fragment>
<div>{this.state.first} 곱하기 {this.state.second}는?</div>
<form onSubmit= {this.onSubmit}>
<input ref={(c) => {this.input = c;}} type="number" value={this.state.value} onChange={this.onChange}/>
<button type="submit">입력</button>
</form>
<div>{this.state.answer}{this.state.result}</div>
</React.Fragment>
);
}
}
</script>
<script type="text/babel">
ReactDOM.createRoot(document.querySelector("#root")).render(<GuGuDan/>)
</script>
</body>