[FIFAPulse] 개발기록 - 전역 context 메모이제이션 하기

조민호·2023년 4월 27일
0

문제 상황


eslint 설정을 진행하던 도중 ,

전역 context를 사용하던 모든 부분에서 아래와 같은 에러가 발생했다

The object passed as the value prop to the Context provider (at line 9) changes every render. To fix this consider wrapping it in a useMemo hook.

이 에러는 React Context API에서 제공하는 Provider 컴포넌트에 전달되는 value prop이 매 렌더링마다 변경되는 경우에 발생한다고 한다



해결


  • 그냥 ESLint 옵션 자체를 off나 warn으로 해버려도 된다

  • 그렇지만 메모이제이션 자체가 긍정적인 효과를 가져다 주기도 하며 , 무작정 옵션을 끄는 것을 지양하고자 메모이제이션을 진행해보기로 했다


useMemo 훅은 이전에 계산된 값을 캐시하고, 다음 렌더링에서 함수에서 반환 된 값을 재사용할 수 있도록 해주므로

useMemo 훅을 사용하여 Provider에 전달되는 객체를 메모이제이션 해 보았다

LoginContext.tsx

import React, { createContext, useState, useContext, useMemo } from 'react';
import { LoginContextValue } from '../../types/context';

export const LoginContext = createContext<LoginContextValue | null>(null);

export const LoginProvider = ({ children }: { children: React.ReactNode }) => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

	// useMemo 사용
  const memoValue = useMemo(() => {
    return { isLoggedIn, setIsLoggedIn };
  }, [isLoggedIn]);

  return <LoginContext.Provider value={memoValue}>{children}</LoginContext.Provider>;
};

export function useLoginAPI() {
  return useContext(LoginContext);
}

ModalContext.tsx

import React, { createContext, useContext, useMemo, useState } from 'react';
import { ModalContextValue } from '../../types/context';

export const ModalContext = createContext<ModalContextValue | null>(null);

export const ModalProvider = ({ children }: { children: React.ReactNode }) => {
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [modalContents, setModalContents] = useState((<></>) as React.ReactNode);

  const openModal = (children: React.ReactNode) => {
    setIsModalOpen(true);
    setModalContents(children);
  };

  const closeModal = () => setIsModalOpen(false);

  const onDimmerClick = (event: React.MouseEvent<HTMLDivElement>) => {
    if (event.currentTarget !== event.target) return;

    closeModal();
  };

	// useMemo 사용
  const memoValue = useMemo(() => {
    return { isModalOpen, openModal, closeModal };
  }, [isModalOpen]);
  return (
    <ModalContext.Provider value={memoValue}>
      {children}
      {isModalOpen && <div>{modalContents}</div>}
    </ModalContext.Provider>
  );
};

export function useModalAPI() {
  return useContext(ModalContext);
}

UserObjContext.tsx

import React, { createContext, useState, useContext, useMemo } from 'react';
import { userObjType, UserObjContextValue } from '../../types/context';

export const UserObjContext = createContext<UserObjContextValue | null>(null);

export const UserObjProvider = ({ children }: { children: React.ReactNode }) => {
  const [userObj, setUserObj] = useState<userObjType | null>(null);

	// useMemo 사용
  const memoValue = useMemo(() => {
    return { userObj, setUserObj };
  }, [userObj]);

  return <UserObjContext.Provider value={memoValue}>{children}</UserObjContext.Provider>;
};

export function useUserObjAPI() {
  return useContext(UserObjContext);
}

각 context의 value로 사용되는 값들을 useMemo훅으로 감싸주고

이로부터 나오는 결과값을 value에 지정해 주었다

profile
웰시코기발바닥

0개의 댓글