서론
React에서 상태 관리를 위해 useState는 매우 자주 사용되는 훅이다. 하지만 이 훅들을 잘못 사용하면 예기치 않은 동작이나 성능 문제를 일으킬 수 있다. 이 글에서는 useState를 사용할 때 흔히 저지르는 실수들과 그 해결 방법을 다룰 것이다.
1. setState는 즉시 실행되지 않는다
useState로 상태를 업데이트할 때 흔히 착각하는 부분은 setState가 즉시 상태를 업데이트한다고 생각하는 것이다. 하지만 React는 여러 상태 업데이트 요청을 모아서 한 번에 처리하는 특성을 갖고 있다. 아래 예제 코드를 보자.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
// ❌ 두 번 증가시키고 싶지만 실제로는 한 번만 증가함
const incrementTwice = () => {
setCount(count + 1);
setCount(count + 1);
};
// ✅ 두 번 증가함
const incrementTwice = () => {
setCount((prevCount) => prevCount + 1);
setCount((prevCount) => prevCount + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={incrementTwice}>Increase Twice</button>
</div>
);
}
위 예시에서 두 번 setCount를 호출해도 count는 한 번만 증가한다. 이는 React가 상태 업데이트를 비동기적으로 처리하고, 최종적으로 한 번의 렌더링으로 묶기 때문이다. 이를 해결하려면 setState에 콜백 함수를 전달해야 한다.
2. 객체 상태를 업데이트할 때는 spread 연산자를 사용하라
리액트에서는 객체 상태를 업데이트할 때 불변성 때문에 새로운 객체를 생성한다. 따라서 객체의 값을 업데이트 해야할때는 spread 연산자를 사용하는 것이 좋다.
import React, { useState } from 'react';
function Example() {
const [data, setData] = useState({ a: 1, b: 2 });
// ❌ 기존 값을 덮어쓰기 때문에 b는 사라지고 a만 3으로 업데이트됨
const updateDataWrong = () => {
setData({ a: 3 });
};
// ✅ 기존 b는 유지하면서 a만 변경
const updateDataCorrect = () => {
setData((prevData) => ({ ...prevData, a: 3 }));
};
return (
<div>
<button onClick={updateDataWrong}>Update (Wrong)</button>
<button onClick={updateDataCorrect}>Update (Correct)</button>
<p>{data.a}</p>
<p>{data.b}</p>
</div>
);
}
3. useState 여러 개 대신 객체를 활용하라
여러 개의 useState를 사용하는 대신 하나의 객체를 상태로 관리할 수 있다. 이 방법은 상태가 서로 관련이 있을 때 유용하다.
import React, { useState } from 'react';
function Form() {
const [formData, setFormData] = useState({ name: '', age: '' });
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
return (
<div>
<input name="name" value={formData.name} onChange={handleChange} />
<input name="age" value={formData.age} onChange={handleChange} />
</div>
);
}
4. 상태나 props로부터 계산된 값을 새로운 상태로 만들 필요는 없다
예를 들어, total이라는 상태를 갖고 있고, 이 상태로부터 price를 계산한다고 가정하자. 새로 상태를 만들어서 관리하는 대신, 기존 상태로부터 계산된 값을 사용하는 것이 더 효율적이다.
import React, { useState } from 'react';
function Example() {
const [total, setTotal] = useState(100);
const price = total * 5; // 새로 상태를 만들 필요 없음
return (
<div>
<p>Total: {total}</p>
<p>Price: {price}</p>
</div>
);
}
total이 변경될 때마다 컴포넌트는 재렌더링되므로 price는 total의 변경된 값을 기준으로 다시 계산된다. 따라서 price도 자동으로 업데이트되므로, 불필요한 상태 업데이트를 줄일 수 있다.
Reference
https://react.dev/learn/you-might-not-need-an-effect
https://react.dev/reference/react/useEffect#fetching-data-with-effects
'React' 카테고리의 다른 글
컴포넌트 구성은 훌룡합니다 그런데 (3) | 2024.09.26 |
---|---|
React Hook을 사용할 때 실수들 (2): useEffect (2) | 2024.09.10 |
React Hook 이해하기 (4): useMemo, useCallback (0) | 2024.09.10 |
React Hook 이해하기 (3): useRef (0) | 2024.09.10 |
React Hook 이해하기 (2): useEffect (0) | 2024.09.10 |