문제

Message 하나를 우클릭해서 contextMenu 열고 닫을 때 마다 모든 Message 가 재실행된다.

//Chat.tsx
    const [menuState, setMenuState] = useRecoilState<contextMenuInterface>(contextMenuState);
    ...
    return (
        <>
            {user.sub !== "0" &&
                <S.BodyContent>
                    <S.Container>
                        <S.Chat>
                            <ChatInfo />
                            <Messages />
                            {menuState.show &&
                                <SMenu.CloseWrapper onClick={closeWrapperHandler} >
                                    <ContextMenu x={menuState.x} y={menuState.y} />
                                </SMenu.CloseWrapper>
                            }
                        </S.Chat>
                    </S.Container>
                </S.BodyContent>
            }
        </>
    )

Chat 컴포넌트 구성은 다음과 같고 Messages 안에는 Message 컴포넌트가 있다.

//Message.tsx
    const [menuState, setMenuState] = useRecoilState<contextMenuInterface>(contextMenuState);
    ...
    const msgPContextHandler = (e: React.MouseEvent<HTMLParagraphElement>) => {
        e.preventDefault();
        const { clientX, clientY } = e;
        setMenuState({
            show: true,
            x: clientX.toString(),
            y: clientY.toString(),
            msg: { id: e.currentTarget.id },
        })
    }

Message 컴포넌트에서 message p태그 우클릭시 동작하는 핸들러인데

Chat에 ContextMenu 컴포넌트를 두었기 때문에 전역 상태관리인 recoil을 사용한 setMenuState를 사용했다.

 

여기서 문제는 모든 Message 컴포넌트에 menuState가 선언되기 때문에 하나의 Message 컴포넌트에서 setMenuState를 하면 모든 Message 컴포넌트가 재실행된다는 점이다.

해결

ContextMenu 컴포넌트는 하나만 존재하는게 낫겠지하고 Chat으로 빼놨던건데 다시 생각해보니 항상 Dom에 그려지는 것도 아니고 모든 Message 컴포넌트의 재실행을 필연적으로 만들고 있었다.

//Messag.tsx
        {menuState.show &&
            <SMenu.CloseWrapper onClick={closeWrapperHandler} >
                <ContextMenu x={menuState.x} y={menuState.y} />
            </SMenu.CloseWrapper>
        }

Chat에서 Message에 ContextMenu 컴포넌트를 옮겼고 recoil이 아닌 useState로 각 Message별로 상태를 만들었다.

ContextMenu를 실행한 Message만 실행되는 것을 볼 수 있다.

의문

다만 message 하나에서 동작할 때 모든 message가 재실행되는 건 막았지만 가상Dom이 보고있는 state가 늘어난건데 state가 자주 변하지 않는다면 많이 늘어나도 되는지 의문이다.