프론트엔드 개발에서 React는 많은 개발자들에게 인기 있는 라이브러리입니다. 그러나 React의 상태 관리와 관련하여 자주 저지르는 실수가 몇 가지 있습니다. 이 블로그 포스트에서는 React에서 상태 업데이트를 할 때 발생할 수 있는 일반적인 오류와 그 해결법에 대해 알아보겠습니다.

1. 상태 업데이트의 비동기성

React에서 상태를 업데이트할 때, setState 함수는 비동기로 작동합니다. 이는 다음 상태값이 즉시 업데이트되지 않음을 의미합니다. 이로 인해 상태 업데이트 직후에 이전 상태를 참조하게 되면, 예상치 못한 결과를 초래할 수 있습니다.

예제

import React, { useState } from 'react';

const Counter = () => {
    const [count, setCount] = useState(0);

    const increment = () => {
        setCount(count + 1);
        console.log(count); // 예상한 값보다 한 단계 이전의 값이 출력됨
    };

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={increment}>Increment</button>
        </div>
    );
};

해결법

이 문제를 해결하기 위해, 상태 업데이트 함수에 함수를 전달하여 이전 상태를 기반으로 새 상태를 계산할 수 있습니다.

const increment = () => {
    setCount(prevCount => prevCount + 1);
    console.log(count); // 이제는 이전 상태를 기반으로 업데이트됨
};

2. 배열 상태의 불변성 유지

React에서는 상태를 직접 수정하는 것이 아니라 새로운 상태를 반환해야 합니다. 배열 상태를 업데이트할 때 이 점을 간과하면 원치 않는 결과를 초래할 수 있습니다.

예제

const TodoList = () => {
    const [todos, setTodos] = useState(['할일1', '할일2']);

    const addTodo = (newTodo) => {
        todos.push(newTodo); // 상태를 직접 수정
        setTodos(todos); // 원치 않는 결과 발생
    };

    return (
        <div>
            <ul>
                {todos.map((todo, index) => (
                    <li key={index}>{todo}</li>
                ))}
            </ul>
            <button onClick={() => addTodo('할일3')}>Add Todo</button>
        </div>
    );
};

해결법

배열 상태를 업데이트할 때는 기존 배열을 복사한 후, 새로운 요소를 추가하여 새로운 배열을 반환해야 합니다.

const addTodo = (newTodo) => {
    setTodos(prevTodos => [...prevTodos, newTodo]); // 불변성 유지
};

3. 상태 업데이트가 여러 번 호출될 때

React에서 상태 업데이트가 여러 번 호출되면, 예기치 않은 결과가 발생할 수 있습니다. 특히 이벤트 핸들러에서 상태를 업데이트할 때 주의해야 합니다.

예제

const MultiIncrement = () => {
    const [count, setCount] = useState(0);

    const increment = () => {
        setCount(count + 1);
        setCount(count + 1); // 두 번 호출하여 의도한 값보다 더 증가
    };

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={increment}>Increment</button>
        </div>
    );
};

해결법

상태 업데이트가 여러 번 호출될 경우, 이전 상태를 기반으로 업데이트를 하여 문제를 해결할 수 있습니다.

const increment = () => {
    setCount(prevCount => prevCount + 1);
    setCount(prevCount => prevCount + 1); // 이제 올바르게 두 번 증가
};

4. useEffect의 의존성 배열

useEffect 훅을 사용할 때 의존성 배열을 잘못 설정하면 의도한 대로 상태가 업데이트되지 않거나 무한 루프에 빠질 수 있습니다.

예제

const Example = () => {
    const [count, setCount] = useState(0);

    useEffect(() => {
        console.log(count);
        setCount(count + 1); // 무한 루프
    }, []); // 의존성 배열이 비어있어 count의 변화가 반영되지 않음

    return <div>{count}</div>;
};

해결법

정확한 의존성을 명시하여 상태 변화에 맞게 효과를 설정하는 것이 중요합니다.

useEffect(() => {
    console.log(count);
}, [count]); // count가 변경될 때마다 효과가 호출됨

마무리

React에서 상태 업데이트를 할 때 주의해야 할 몇 가지 실수와 그 해결법에 대해 알아보았습니다. 상태 업데이트의 비동기성, 배열 상태의 불변성, 상태 업데이트의 여러 번 호출, 그리고 useEffect의 의존성 배열 등 다양한 요소들이 있습니다. 이러한 점들을 염두에 두고 작업한다면 보다 안정적이고 예측 가능한 React 애플리케이션을 개발할 수 있을 것입니다.