React의 useState 후크는 기능적 구성 요소의 상태를 관리하는 데 필수적인 도구이지만 몇 가지 일반적인 함정에 빠지기 쉽습니다. React를 막 시작했든 오랫동안 사용해 왔든, 이러한 실수를 피하면 예상치 못한 버그와 성능 문제로부터 벗어날 수 있습니다.
자주 발생하는 10가지 실수와 이를 방지하여 더욱 깔끔하고 효율적인 코드를 작성하는 방법을 살펴보겠습니다.
가장 일반적인 문제 중 하나는 초기 상태 유형이 상태 업데이트 중에 예상되는 유형과 일치하지 않을 때 발생합니다.
❌ 실수: 초기 상태 유형 불일치
const [count, setCount] = useState(0); setCount("1"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.
✅ 해결책: TypeScript를 사용하거나 유형을 명시적으로 지정하세요.
const [count, setCount] = useState(0); setCount(1); // No issues now.
이전 값을 기반으로 상태를 업데이트할 때 현재 상태를 직접 참조하면 특히 비동기 작업에서 오래된 값이 발생할 수 있습니다.
❌ 실수: 현재 상태를 직접 사용
setCount(count 1); // Can cause bugs in async scenarios.
✅ 해결책: 안전한 업데이트를 위해 기능적 형식을 사용하세요.
setCount((prevCount) => prevCount 1); // Ensures you always have the latest value.
다른 상태나 소품에서 파생될 수 있는 상태에 값을 저장하지 마세요. 이로 인해 불필요한 다시 렌더링 및 동기화 문제가 발생할 수 있습니다.
❌ 실수: 파생 상태 저장
const [count, setCount] = useState(0); const [doubleCount, setDoubleCount] = useState(count * 2);
✅ 해결책: 상태를 사용하는 대신 렌더링 중에 값을 파생시킵니다.
const [count, setCount] = useState(0); const doubleCount = count * 2; // No need to store this in state.
렌더링 단계 내에서 setState를 호출하면 무한 루프 및 성능 문제가 발생합니다.
❌ 실수: 렌더링 중 상태 설정
const [count, setCount] = useState(0); setCount(1); // Infinite loop!
✅ 해결책: 이벤트 핸들러나 효과에서 상태 변경을 트리거합니다.
const handleClick = () => setCount(1);
React는 특히 배열이나 객체의 경우 상태를 직접 변경하는 경우 변경 사항을 감지하지 않습니다.
❌ 실수: 상태를 직접 변경
const [items, setItems] = useState([1, 2, 3]); items.push(4); // Mutation happens here, React won’t re-render!
✅ 해결 방법: 새 배열이나 객체를 반환하여 다시 렌더링을 실행하세요.
setItems((prevItems) => [...prevItems, 4]); // Spread to create a new array.
복잡한 상태를 처리할 때 적절한 유형을 정의하지 않으면 런타임 문제와 혼란이 발생할 수 있습니다.
❌ 실수: 암시적 유형은 오류로 이어질 수 있습니다.
const [user, setUser] = useState({ name: "", age: 0 }); setUser({ name: "John", age: "thirty" }); // Type error: Age should be a number.
✅ 해결책: 올바른 유형으로 상태의 모양을 정의하세요.
type User = { name: string; age: number }; const [user, setUser] = useState({ name: "", age: 0 });
타이머와 같이 렌더링에 영향을 주지 않는 값에 useState를 사용하면 불필요한 다시 렌더링이 발생합니다.
❌ 실수: 변경 가능한 값에 상태 사용
const [timerId, setTimerId] = useState(null);
✅ 해결책: 다시 렌더링할 필요가 없는 변경 가능한 값에는 useRef를 사용하세요.
const timerIdRef = useRef(null);
클래스 구성 요소와 달리 useState는 업데이트를 자동으로 병합하지 않습니다. 이를 잊어버리면 상태의 일부를 덮어쓰게 될 수 있습니다.
❌ 실수: 병합하는 대신 상태 덮어쓰기
const [user, setUser] = useState({ name: '', age: 0 }); setUser({ age: 25 }); // The 'name' field is now lost!
✅ 해결 방법: 스프레드 연산자를 사용하여 상태 업데이트를 병합하세요.
setUser((prevUser) => ({ ...prevUser, age: 25 })); // Merges with existing state.
상태의 창 크기와 같은 빈도가 높은 값을 추적하면 과도한 재렌더링으로 인해 성능 문제가 발생할 수 있습니다.
❌ 실수: 빈번한 업데이트를 위해 상태 사용
const [size, setSize] = useState(window.innerWidth); window.addEventListener("resize", () => setSize(window.innerWidth));
✅ 해결책: 성능 저하를 줄이려면 useRef 또는 debounce를 사용하세요.
const sizeRef = useRef(window.innerWidth); useEffect(() => { const handleResize = () => { sizeRef.current = window.innerWidth; }; window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []);
React 상태 업데이트는 비동기식이지만 많은 개발자는 변경 사항이 즉시 적용된다고 잘못 가정합니다.
❌ 실수: 상태 변경이 즉시 발생한다고 가정
setCount(count 1); console.log(count); // Logs the old value, not the updated one!
✅ 해결책: useEffect를 사용하여 상태 변경을 추적하고 최신 값이 사용되는지 확인하세요.
useEffect(() => { console.log(count); // Logs the updated value after re-render. }, [count]);
이러한 useState 함정을 피하면 React 코드가 더욱 강력하고 읽기 쉽고 성능이 좋아집니다. React의 상태 메커니즘이 어떻게 작동하는지 이해하고 모범 사례를 알면 디버깅 시간을 절약하고 전반적인 개발 경험을 향상할 수 있습니다.
공유할 useState 팁이나 실수가 있나요? 아래 댓글에 남겨주세요! ?
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3