State
1. 정의와 개념
- state란 지속적으로 상태를 관리할 수 있는 변수를 의미한다. 기존 JavaScript의 let, const로 선언한 변수는 화면이 Re-rendering 될 때 그 값이 초기화 되었지만, state로 선언된 변수는 React가 관리하기 때문에 화면이 Re-rendering 되어도 값이 계속 유지된다.
- state는 컴포넌트 안에서 관리되며, 컴포넌트는 state의 값이 바뀔 때 마다 화면을 Re-rendering 한다.
2. state 사용의 차이: 함수형 컴포넌트 vs 클래스 컴포넌트
결론부터 말하자면 React 공식 문서에서 함수형 컴포넌트와 useState(React Hook)을 사용할 것을 권장한다.
개념적으로 React 컴포넌트는 항상 함수에 더 가깝습니다. Hook은 React의 정신을 희생하지 않고 함수의 사용을 권장합니다.
Conceptually, React components have always been closer to functions. Hooks embrace functions, but without sacrificing the practical spirit of React.
출처: React Docs - Introducing Hooks
이유는 React 클래스형 컴포넌트를 사용할 때 this 키워드를 이용하게 되는데 JavaSciprt의 this는 대부분의 타 언어와 다르게 작동하며 코드의 재사용성과 구성을 어렵게 만들고 그 외에도 클래스로 인해 부가적인 문제가 발생하기 때문이다.
초기 React는 state와 lifecycle을 관리하려면 클래스형 컴포넌트에서만 가능했고 함수형 컴포넌트는 UI 표현만 가능했다. 하지만 React 16.8 버전부터 모든 컴포넌트를 함수형으로 만들 수 있게 되었고, React Hook을 이용해서 함수형 컴포넌트에서도 state와 lifecycle을 관리할 수 있게 되었다.
함수형 컴포넌트에서 state 사용: with useState
1. 문법
- useState는 React Hook 중 한 가지이며, 함수형 컴포넌트에서 state를 관리하기 위해 사용한다.
- setter함수명(클래스형 컴포넌트의 setState)은 자유롭게 작명 가능하지만, 'set변수명'으로 작성하는게 관례
- useState(초기값)에서 초기값을 사용하지 않아도 됨
- const 대신 let을 사용해도 무관
const [변수명, setter함수명] = useState(초기값);
예) const [fruit, setFruit] = useState('Citron');
- 주의: state 업데이트는 비동기적이므로 순차 진행이 필요할 땐 async, await 또는 updater 함수를 사용해야 한다.
→ 2021.10.18 - [Front-End/React] - [React] setState의 비동기 동작: async, await 및 updater 함수 사용 - 예시 코드
import React, { useState } from "react";
const App = () => {
let hello = "Welcome to Citron Banana Blog!";
// useState를 사용하여 state 정의
const [count, setCount] = useState(0);
const add = () => {
setCount(count + 1); // setter 함수를 사용해 값 변경
};
const remove = () => {
if (count <= 0) {
return;
}
setCount(count - 1); // setter 함수를 사용해 값 변경
};
return (
<div>
<h1>{hello}</h1>
<h2>Example: state 사용</h2>
<div style={{ fontSize: 15 }}>Citron을 장바구니에 담겠습니까?</div>
<button style={{ fontSize: 15, margin: 5 }} onClick={add}>
add
</button>
<button style={{ fontSize: 15 }} onClick={remove}>
remove
</button>
<br />
<br />
<br />
<div style={{ fontSize: 15, color: "blue" }}>
장바구니에 담긴 Citron 개수: {count}
</div>
</div>
);
};
export default App;
2. Object, Array를 State로 사용할 경우
- Object 또는 Array와 같이 내부 element를 갖는 자료구조를 State로 정의한다면 내부 element의 변화를 관리하는 것이 일반적인 목적일 것이다.
- 이 때 기존에 정의한 객체(Object, Array)에 element를 수정 후 setter 함수를 이용하는 것이 아닌, 반드시 새로운 객체를 정의한 후 setter 함수를 이용해야 함에 주의하자.
Wrong Case
- changeName 함수를 보면 기존에 생성된 객체인 person의 name 속성의 값을 "Banana"로 수정하고 setter 함수인 setPersonState를 사용했다. 하지만 실제로 change 버튼을 눌러보면 Citron은 Banana로 변경되지 않는다.
- 이유는 React가 Re-rendering이 되기 위해선 state 자체가 변경되어야 하는데, state 자체는 person이라는 객체이고 person의 name 속성 값이 변경되었을 뿐 person 객체는 그대로이기 때문에 Re-rendering하지 않는 것이다.
- 따라서 새로운 객체를 정의해 name을 변경한 후 setPersonState을 사용해야한다. → Correct Case
import React, { useState } from "react";
const App = () => {
const person = {
name: "Citron",
age: 20,
};
const [personState, setPersonState] = useState(person);
const changeName = () => {
person.name = "Banana"; // 기존 객체 person에 값을 수정한 후
setPersonState(person); // setter 함수를 사용 → 화면 변화 없음
};
return (
<div>
<h1>Name을 Banana로 변경</h1>
<div>
<button onClick={changeName}>change</button>
<h2>{personState.name}</h2>
</div>
</div>
);
};
export default App;
Correct Case
- 새로운 Object 타입의 객체 newPerson을 생성한 후 name 속성을 수정해 setPersonState 함수를 사용했다.
- 화면에서 Citron → Banana로 잘 변경되는 것을 확인할 수 있다.
import React, { useState } from "react";
const App = () => {
const person = {
name: "Citron",
age: 20,
};
const [personState, setPersonState] = useState(person);
const changeName = () => {
const newPerson = { person }; // 새로운 객체 newPerson을 정의
newPerson.name = "Banana"; // name 속성에 "Banana" 할당
setPersonState(newPerson); // 새로운 객체를 setter 함수에 사용 → Re-rendering
};
return (
<div>
<h1>Name을 Banana로 변경</h1>
<div>
<button onClick={changeName}>change</button>
<h2>{personState.name}</h2>
</div>
</div>
);
};
export default App;
클래스형 컴포넌트에서 state 사용
레거시 코드에는 여전히 클래스형 컴포넌트에서 state를 사용한 흔적이 남아 있을 수 있으므로 학습한다.
1. 문법
- state는 Object 타입이다.
- state 변경 함수: setState()
- state에 정의한 변수의 값을 수정할 땐 setState()를 사용한다. setState()를 호출하면 React는 state를 refresh하고 render function을 호출해 UI를 Rerendering하게 된다.
- state값을 사용할 땐 가 아닌 = 기호를 써서 값을 직접 수정하면 안된다. 값을 직접 수정하면 React는 render 함수를 refresh 하지 않기 때문이다.
- setState() 내에서 state 값을 변경할 땐 1) state 객체에 직접 접근 방식과 2) Callback 함수 방식 두 가지가 있다. 1번은 setState 함수 외부를 참조하는 방식이므로 2번 Callback 함수를 사용하는 것이 권장된다
- state에 없는 속성(예시 코드에서 count가 아닌 속성)을 setState() 내에 작성할 경우 state에 해당 속성이 추가된다
- 예시 코드
import React, { Component } from "react";
class App extends Component {
hello = "Welcome to Citron Banana Blog!";
// state 정의
state = {
count: 0,
};
// state.count += 1
add = () => {
// setState() 이용하여 state 변경: 1) state 객체에 직접 접근
this.setState({ count: this.state.count + 1 });
};
// state.count -= 1
remove = () => {
if (this.state.count > 0) {
// setState() 이용하여 state 변경: 2) callback 함수를 이용. 이 때 current는 this.state
this.setState((current) => ({ count: current.count - 1 }));
}
};
render() {
return (
<div>
<h1>{this.hello}</h1>
<h3>Example: state 사용</h3>
<div>Citron을 장바구니에 담겠습니까?</div>
<button onClick={this.add}> add </button> // add 버튼 클릭시 add 함수 호출
<button onClick={this.remove}> remove </button> // remove 버튼 클릭시 remove 함수 호출
<div>----------------------------------</div>
<div>장바구니에 담긴 Citron 개수: {this.state.count}</div>
</div>
);
}
}
export default App;
[Reference: Official Document]
State and Lifecycle: State 설명
https://ko.reactjs.org/docs/state-and-lifecycle.html
Using the State Hook: State 사용
https://ko.reactjs.org/docs/hooks-state.html
Hook의 개요: React Hook 개발 이유 및 클래스 컴포넌트의 문제점 극복
https://ko.reactjs.org/docs/hooks-intro.html
'Front-End > React' 카테고리의 다른 글
[React] react-router-dom: React에서 페이지 이동 (0) | 2021.10.18 |
---|---|
[React] JSX에서 if, for(map) 사용하기(JavaScript) (0) | 2021.10.17 |
[React] Props 기초 (0) | 2021.10.17 |
[React] export와 export default의 차이 (0) | 2021.10.04 |
[React] 시작하기(Requirements, Create React App) (0) | 2021.10.03 |