aiResponse가 오면 노드의 위치를 계산해서 이를 바탕으로 updateNode를 해 주는 작업을 진행해야 했음

근데 aiResponse가 왔을 때, updateNode가 한 번이 아니라 n회 일어나는 것을 확인할 수 있었음

ai에게 요청을 보내기 위한 input의 조작 횟수가 많아질수록, updateNode의 호출 횟수도 많아졌음

해당 문제는 이전에 있던 것들과 마찬가지로… 이벤트 핸들러가 중복으로 등록되어서 발생하는 문제임

socket?.on("joinRoom", (initialData) => {
      setLoading(true);
      setTimeout(() => {
        setData({ ...initialData.nodeData });
        overrideHistory(JSON.stringify(initialData));
        initializeTitle(initialData);
        initializeContent(initialData);
        setLoading(false);
      }, 0);
    });

    socket?.on("updateNode", (updatedNodeData) => {
      console.log("updatedNodeData", updatedNodeData);
      overrideNodeData(updatedNodeData);
    });

    socket?.on("updateTitle", (updatedTitle) => {
      updateTitle(updatedTitle.title);
    });

    socket?.on("updateContent", (updatedContent) => {
      updateContent(updatedContent.content);
    });

    socket?.on("disconnect", () => {
      setData({});
      overrideHistory(JSON.stringify({}));
      setLatestMindMap(mindMapId);
    });

    socket?.on("aiResponse", (response) => {
      const initializedNodes = initializeNodePosition(response);
      handleSocketEvent({
        actionType: "updateNode",
        payload: initializedNodes,
        callback: (response) => {
          overrideNodeData(response);
        },
      });
    });

이 친구들이 nodeListProvider에 있는 이벤트 핸들러들인데, socket io 학습 및 로직 작성 극초기에 넣은 것들이라 useEffect 바깥에 있었음

원래 useEffect에 언젠가는 넣어야지… 생각하고 있었는데 리팩토링이 늦어져서 결국 버그가 터진 것… 🥲

해당 코드는 nodeData가 업데이트 될 때마다 실행이 됨, 즉 nodeData가 업데이트 될 때마다 이벤트가 등록되는 것

하지만 cleanup이 되지 않기 때문에 input에 change가 일어날 때마다 핸들러가 하나씩 중복으로 등록 되고, 이게 aiResponse가 왔을 때 한 방에 터지니까 updateNode도 우르르 갔던 것이었다

그래서 이걸 원래 리팩토링 하려고 했던 방법대로, useEffect 내부에 선언해 봄

  useEffect(() => {
    socket?.on("joinRoom", (initialData) => {
      setLoading(true);
      setTimeout(() => {
        setData({ ...initialData.nodeData });
        overrideHistory(JSON.stringify(initialData));
        initializeTitle(initialData);
        initializeContent(initialData);
        setLoading(false);
      }, 0);
    });

    socket?.on("updateNode", (updatedNodeData) => {
      console.log("updatedNodeData", updatedNodeData);
      overrideNodeData(updatedNodeData);
    });

    socket?.on("updateTitle", (updatedTitle) => {
      updateTitle(updatedTitle.title);
    });

    socket?.on("updateContent", (updatedContent) => {
      updateContent(updatedContent.content);
    });

    socket?.on("disconnect", () => {
      setData({});
      overrideHistory(JSON.stringify({}));
      setLatestMindMap(mindMapId);
    });

    socket?.on("aiResponse", (response) => {
      const initializedNodes = initializeNodePosition(response);
      handleSocketEvent({
        actionType: "updateNode",
        payload: initializedNodes,
      });
    });

    return () => {
      socket?.offAny();
    };
  }, [socket]);

return되면서 컴포넌트가 unmount될 때, 모든 이벤트에 대한 리스너를 없애버리도록 함

이렇게 하니 updateNode 이벤트가 한 번만 잘 갔음

그런데… updateNode 이벤트가 와도 화면상 나타나지 않는 문제가 생김

사실 이걸 해결하기 위한 방법은 간단함