firebase onSnapshot react prevState

이영욱·2023년 11월 2일

firebase의 firestore를 이용해 개발을 진행하던 도중, useEffect 내에 실시간으로 추가, 수정, 삭제 되는 데이터를 전역 상태로 보관하는 코드를 작성했다.

처음에는 당연히 아래와 같이 useEffect 훅 내에서 컴포넌트에서 가지고 있는 가장 최신 state Snapshot을 가지고 올 수 있을거라고 생각했다.

const [state, setState] = useState([])

useEffect(() => {
	setState([...state, ...ArrayData])
}, [ArrayData])

하지만 firebase onSnapshot 메서드를 통해 실시간 통신을 진행할 경우 ...state를 이용할 수 없었고, 아래처럼 setState의 prevState 인자를 이용해야 했다.

아래는 Map 객체로 관리하고 있는 recoil state를 업데이트 하는 코드이다.

const setKanbanDataState = useSetRecoilState(kanbanState);

useEffect(() => {
  ...
  ...
  const kanbanQuery = query(
    collection(db, "project", pathname, "data"),
    where("is_deleted", "==", false),
  );
  const unsubKanban = onSnapshot(kanbanQuery, (kanbanSnapshot) => {
    const addedMap = new Map();
    kanbanSnapshot.docChanges().forEach((change) => {
      // 최초 Snapshot 생성 혹은 사용자가 직접 칸반을 추가했을 때
      if (change.type === "added") {
        addedMap.set(change.doc.id, change.doc.data());
      }
      // 칸반을 수정할 경우
      if (change.type === "modified") {
        setKanbanDataState((prev) => {
          prev.set(change.doc.id, change.doc.data());
          return new Map([...prev]);
        });
      }
      // 칸반이 삭제된 경우 (is_deleted 수정 시 쿼리 결과 변경)
      if (change.type === "removed") {
        setKanbanDataState((prev) => {
          prev.delete(change.doc.id);
          return new Map([...prev]);
        });
      }
    });
    if (addedMap.size > 0) {
      setKanbanDataState((prev) => new Map([...prev, ...addedMap]));
    }
  });
  ...
  ...
}, [])

그럼 prevState는 뭘 하는 녀석일까?

react의 setState는 기본적으로 비동기적으로 실행된다. 성능상 이점을 가져가기 위해 리액트에서 여러개의 setState를 묶어서 실행시키기 때문인데,
이때 setState의 prevState를 활용하게 된다면 이전 state를 확정적으로 가져올 수 있다.

따라서 이전 state가 로직 내에서 반드시 필요하다면 prevState를 사용하는 것이 권장된다.

profile
다양한 경험을 통해 성장하는 개발자, 이영욱 입니다.

0개의 댓글