[React] Context에 useMemo 사용하여 불필요한 리렌더링 방지하기

nemo·2022년 4월 5일
5

React

목록 보기
14/28

Context API란?

Context API는 전역으로 데이터를 공유할 수 있도록 고안된 방법이다.
사용자 정보나, 테마, 언어 등 전역적인 데이터를 관리하기에 용이하다.


Context API 단점

Context가 전송하는 value 데이터는 객체 형태이다. 따라서 객체에서 하나의 데이터만 변경되어도 Provider로 감싼 모든 자식 컴포넌트에서 리렌더링이 일어난다.


해결 방법

  1. Context 데이터를 가지고 있는 컴포넌트에 useMemo hook을 이용하여 데이터를 캐싱하여 불필요한 리렌더링 방지

  2. Context를 쪼개서 여러 개 사용

  3. React.memo 고차함수 사용하여 자식 컴포넌트의 불필요한 리렌더링 방지


useMemo 사용하여 해결하기

위 해결 방법 중 useMemo hook을 사용하는 방법에 대해 정리해보도록 하겠다.

GlobalState.js는 Context Provider 컴포넌트를 생성한다.

(GlobalState.js)

import React, { createContext } from 'react';

// initial state
const initialState = {
  ...
};

// create context
export const GlobalContext = createContext(initialState);

...

// provider components
export const GlobalProvider = (props) => {
  return (
    <GlobalContext.Provider value={{ 
        watchlist: { ... }, // object 데이터
        addMovieToWatchlist, // 함수
    }}>
      {props.children}
    </GlobalContext.Provider>
  )
}

기존에는 자식 컴포넌트에 전달하는 value를 객체 그대로 작성하였다.
저 중에 하나라도 변경되면 Provider로 감싼 자식 컴포넌트는 그 상태를 사용하지 않아도 리렌더링되는 문제가 있었다.

(GlobalState.js)

import React, { createContext } from 'react';

// initial state
const initialState = {
  ...
};

// create context
export const GlobalContext = createContext(initialState);

...

// useMemo 사용
const value = React.useMemo(() => ({ 
  watchlist: { ... }, // object 데이터
  addMovieToWatchlist, // 함수
}), [watchlist, addMovieToWatchlist]);

// provider components
export const GlobalProvider = (props) => {
  return (
    <GlobalContext.Provider value={ value }>
      {props.children}
    </GlobalContext.Provider>
  )
}

useReducer를 사용한다면 아래와 같이 적용하면 된다.

import React, { createContext, useReducer } from 'react';
import AppReducer from './AppReducer';

// initial state
const initialState = {
  ...
};

// create context
export const GlobalContext = createContext(initialState);

...

// useReducer
const [state, dispatch] = useReducer(AppReducer, initialState);


// useMemo 사용
const value = React.useMemo(() => ({ 
  watchlist: { ... }, // object 데이터
  addMovieToWatchlist, // 함수
}), [state]);

// provider components
export const GlobalProvider = (props) => {
  return (
    <GlobalContext.Provider value={ value }>
      {props.children}
    </GlobalContext.Provider>
  )
}

0개의 댓글