단방향 데이터 흐름, setState()리액트 기초/라이프사이클 + State 관리2021. 7. 14. 21:37
Table of Contents
단방향 데이터 흐름
- 데이터는 위에서 아래로, 즉, 부모 컴포넌트에서 자식 컴포넌트로 넘어간다.
- 부모 컴포넌트의 state가 업데이트 되면 자식 컴포넌트도 리렌더링이 일어난다.
- 만약 자식 컴포넌트가 부모 컴포넌트의 state를 고칠 수 있다고 가정하면, 부모 컴포넌트는 state가 변했으니 렌더링이 일어나고 부모가 렌더링이 일어나면 자식도 렌더링이 일어난다. 이 과정이 반복되면 무한 루프에 빠져버려 노답이된다. 이런 경우가 생기지 않게 하기 위해서 무조건 데이터는 단방향으로 흐르는 것을 알아야 하고 부모만 자식을 변경해야 한다!
왜 setState() 함수를 사용할까?
- 예를 들어 어떤 리액트 요소를 클릭했을 때, 컴포넌트의 state 값이 변경되도록 하려고 아래처럼 이벤트를 포함하는 코드를 작성했다고 하자.
import React from 'react';
import './App.css'
class App extends React.Component{
constructor(props){
super(props);
this.state = {
duck: 1
}
}
render(){
return(
<div className="App" onClick={function(){
this.state.duck = 2;
console.log(this.state.duck);
}.bind(this)} style ={{background: 'blue'}}>
<h1>{this.state.duck}
</h1>
</div>
);
}
}
export default App;
- 위 코드를 실행시켜보면 리액트 요소를 클릭했을 때, 이벤트 함수가 this.state.duck = 2 로 state 값을 1에서 2로 변경시켜서 콘솔창에 2가 찍혀도 화면에 나타나는 값은 변하지 않는 것을 알 수 있다.
- 리액트가 state 값이 바뀌었다는 것을 모르기 때문이다.
- 이를 해결하기 위해서 setState를 사용하면 UI와 state가 동시에 정상적으로 업데이트된다.
import React from 'react';
import './App.css'
class App extends React.Component{
constructor(props){
super(props);
this.state = {
duck: 1
}
}
render(){
return(
<div className="App" onClick={function(){
this.setState({duck: 2});
}.bind(this)} style ={{background: 'blue'}}>
<h1>{this.state.duck}
</h1>
</div>
);
}
}
export default App;
setState()
- 클래스형 컴포넌트에서 state를 관리하는 방법.
- 아래처럼 중괄호 안에 변경할 state 요소와 할당할 값을 json 형식으로 key: value 쌍으로 넣어준다.
this.setState({[변경할 state 요소]: [할당할 값]})
- 예를 들어, duck이라는 state의 값을 4로 바꾸면 아래처럼 사용하면된다.
this.setState({duck: 4})
- 만약 render() 함수 바로 아래에 이벤트 없이 setState()를 사용하면 무한루프가 발생한다.
- setState() 호출하면 render()함수가 실행되기 때문이다!
import React from 'react';
import './App.css'
class App extends React.Component{
constructor(props){
super(props);
this.state = {
duck: 1
}
}
render(){
this.setState({duck: 2});
return(
<div className="App" style ={{background: 'blue'}}>
<h1>{this.state.duck}
</h1>
</div>
);
}
}
export default App;
- 아래처럼 이벤트와 같은 것을 사용해서 달아서 조건에 따라 setState가 실행되도록 하자.
import React from 'react';
import './App.css'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
duck: 1
}
}
hi = () => {
this.setState({ duck: 4 });
}
render() {
return (
<div className="App">
<button onClick = {this.hi}>state 변경</button>
</div>
);
}
}
export default App;
주의사항!!!
- 만약 state를 변경하는 함수에 ()를 붙이면 무한루프에 빠지게 된다!
- 아래의 경우 hi()가 state를 변경하는 setState를 포함하는 함수라 가정하면 아래처럼 ()를 붙여서 사용하면 함수를 호출한 것이므로 요소가 렌더링 되자마자 함수가 호출이 된다!
<button onClick = {this.hi()}>state 변경</button>
- 아래처럼 단순히 함수를 선언해서 bind 하거나
<button onClick = {function(){this.hi()}.bind(this)}>state 변경</button>
- 아래처럼 ()를 떼어서 함수를 참조하면 무한루프에 빠지지 않는다!
<button onClick = {this.hi}>state 변경</button>
연습) 버튼을 클릭하면 state가 변경되어서 화면에 네모가 하나 늘어나거나 줄어나는 페이지를 만들어보자
import React from "react";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 3
};
}
componentDidMount() {}
addNemo = () => {
// this.setState로 count를 하나 더해주기!
this.setState({ count: this.state.count + 1 });
};
removeNemo = () => {
// 네모 갯수가 0보다 작지 않을때 count 하나 빼기.
if (this.state.count > 0) {
this.setState({ count: this.state.count - 1 });
}else{
window.alert('네모가 없어요!');
}
};
render() {
const nemo_count = Array.from({ length: this.state.count }, (v, i) => i);
let nemo = nemo_count.map((num, idx) => {
return (
<div
//유니크한 값을 가진 key라는 props가 필요하다.
key={num}
style={{
width: "150px",
height: "150px",
backgroundColor: "#ddd",
margin: "10px",
}}
>
nemo
</div>
);
})
return (
<div className="App">
{nemo}
<div>
<button onClick={this.addNemo}>하나 추가</button>
<button onClick={this.removeNemo}>하나 빼기</button>
</div>
</div>
);
}
}
export default App;
'리액트 기초 > 라이프사이클 + State 관리' 카테고리의 다른 글
createRef() (0) | 2021.07.13 |
---|---|
컴포넌트 라이프사이클 (0) | 2021.07.13 |
@덕구공 :: Duck9s'
주니어 개발자에욤
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!