[React] 왜 의존성 배열의 setState는 동작하지 않을까?

김태민·2025년 12월 1일

문제 상황

Q&A 모달에서 새로운 문의를 작성하면 자동으로 목록이 업데이트되도록 만들고 싶었습니다.
처음에는useEffect의 의존성 배열에 setQnas를 넣으면 될 것 같았습니다. 새로 질문을 작성하면 setQnas가 변경되고, 다시 getMyQnas를 실행하여 새로고침이 가능할 것이라고 생각습니다.

const QnaModal = ({ onClose }: QnaModalProps) => {
  const [qnas, setQnas] = useState([]);

  useEffect(() => {
    getMyQnas((response) => {
      if (response) {
        setQnas(response.list || response);
      }
    });
  }, [setQnas]); // ❌ 이렇게 하면 새로고침이 안된다!

  // ...
}

기대했던 동작:
- 문의 작성 완료 → setQnas 호출 → useEffect 재실행 → 목록 새로고침

-> 동작 안함!

왜 안 되는가?

setState 함수는 절대 변하지 않습니다.

const [qnas, setQnas] = useState([]);

이 함수는 컴포넌트가 생성될 때 한 번만 만들어지고, 절대 변경되지 않습니다.

React의 useState가 반환하는 setter 함수는 항상 동일한 참조를 유지합니다.

  useEffect(() => {
    // 어떤 작업
  }, [setQnas]); // setQnas는 항상 같은 함수 → 변화 감지 안됨

의존성 배열은 "값이 변했을 때" useEffect를 재실행하는데, setQnas는 변하지 않으니 재실행되지 않는 것이죠.


의문점

그럼 의존성 배열에 setQnas가 아니라 qnas를 넣으면 되지 않을까? 라는 생각이 들었습니다.

const QnaModal = ({ onClose }: QnaModalProps) => {
  const [qnas, setQnas] = useState([]);

  useEffect(() => {
    getMyQnas((response) => {
      if (response) {
        setQnas(response.list || response);
      }
    });
  }, [qnas]); // ??
}

하지만 이렇게 할 경우

  1. useEffect 실행

  2. getMyQnas API 호출

  3. setQnas(새로운 데이터) 호출

  4. qnas 값이 변경됨

  5. useEffect가 qnas 변화를 감지

  6. useEffect 다시 실행 (1번으로 돌아감)

    이런 무한 반복이 발생할 수 있습니다.


    어떻게 해결할까?

    제가 선택한 방법은 새로고침 함수 분리 + 필요 시 호출 입니다.

  const QnaModal = ({ onClose }: QnaModalProps) => {
    const [qnas, setQnas] = useState([]);
    const [showCreateForm, setShowCreateForm] = useState(false);

    // 1. 새로고침 로직을 별도 함수로 분리
    const fetchQnas = () => {
      getMyQnas((response) => {
        if (response) {
          setQnas(response.list || response);
        }
      });
    };

    // 2. 처음 마운트 시 한 번만 실행
    useEffect(() => {
      fetchQnas();
    }, []); // 빈 배열

    // 3. 모달 닫을 때 명시적으로 새로고침
    const handleFormClose = () => {
      setShowCreateForm(false);
      fetchQnas(); // 여기서 새로고침!
    };

    // 4. 삭제 후에도 명시적으로 새로고침
    const handleDeleteButton = (qnaId, e) => {
      e.stopPropagation();

      if (!window.confirm("이 문의를 삭제하시겠습니까?")) {
        return;
      }

      deleteMyQnas({ id: qnaId }, (response) => {
        if (response) {
          alert("문의가 삭제되었습니다.");
          fetchQnas(); // 여기서도 새로고침!
        }
      });
    };

    return (
      <>
        {/* ... */}
        <QnaCreateModal
          isOpen={showCreateForm}
          onClose={handleFormClose} // 닫을 때 fetchQnas 호출
        />
      </>
    );
  };

새로고침 함수를 정의해놓고 필요 시 호출하여 사용하면 되니, 더 명확하고 예측이 가능한 동작이 가능했습니다.


정리

setState 함수는 변하지 않으니, useEffect를 통한 데이터 새로고침이 필요할 경우에는 명시적으로 함수를 정의해놓고 필요 시 호출하는 방식을 사용하면 됩니다!

profile
빠르게 성장하는 개발자

0개의 댓글