
React의 useContext를 이용 시 리 렌더링을 막는 방법
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
최근 useContext
를 사용 중 불필요한 리 렌더링을 막는 방법에 관해서 관심이 생겨 직접 확인 해 보았습니다.
준비
먼저 확인을 위해 샘플 코드를 만들어 보겠습니다.
1.먼저 react 프로젝트를 생성합니다.
npm create vite@latest [project-name] -- --template react-ts
2.확인을 위해 관련 component와 context 코드를 작성합니다.
countContext.tsx
import { createContext, useContext } from 'react';
export interface CountContextType {
count: number
countIncrement : () => void
countDecrement : () => void
}
export const CountContext = createContext<CountContextType | undefined>(undefined);
export const useCountContext = (): CountContextType => {
const context = useContext(CountContext);
if (context === undefined) {
throw new Error('must used within CountProvider');
}
return context;
};
Main.tsx
import { useCountContext } from "../countContexts"
export function Main() {
const { count, countIncrement, countDecrement } = useCountContext()
return (
<div>
<div>{count}</div>
<button onClick={countIncrement}>+</button>
<button onClick={countDecrement}>-</button>
</div>
)
}
Header.tsx
export function Header() {
return (
<div>HEADER</div>
)
}
Footer.tsx
export function Footer() {
return (
<div>FOOTER</div>
)
}
App.tsx
import { useCallback, useState } from "react"
import { Header } from "./components/Header"
import { Footer} from "./components/Footer"
import { Main } from './components/Main'
import { CountContext } from "./countContexts"
function App() {
const [count, setCount] = useState(0)
const countIncrement = useCallback(() => {
setCount(count + 1)
},[count])
const countDecrement = useCallback(() => {
setCount(count - 1)
},[count])
return (
<CountContext.Provider value={{ count, countIncrement, countDecrement }}>
<Header />
<Main />
<Footer />
</CountContext.Provider>);
}
export default App
일단 베이스가 되는 코드를 작성했습니다.
위 코드를 실행해 보면useContext
를 이용하고 있는 Main
component뿐만 아닌 Footer
와 Header
component도 함께 리 렌더링 되는 것을 확인 할 수 있습니다.
chrome의 확장 도구인 react developer tools의 profiler를 통해 확인해 보면 아래와 같이 리 렌더링 결과를 확인 할 수 있습니다.
방법1
첫 번째 방법은 React.memo
를 이용하는 방법입니다.
React.memo
를 이용하면 부모 component가 리 렌더링 시 불필요한 리 렌더링을 막을 수 있습니다.
보통 부모 component에서 넘겨주는 props의 변경이 없는 경우 React.memo
를 사용하면 불필요한 리 렌더링을 막을 수 있습니다.
이번 Hedaer
component의 경우에는 아무 props도 넘겨주지 않았기 때문에 리 렌더링이 불필요한 상태입니다.
그럼, 이전 코드의 Header
코드를 수정해 보겠습니다.
Header.tsx
import React from "react"
export const Header = React.memo(() =>{
return (
<div>HEADER</div>
)
})
위와 같이 코드를 작성 후 profiler에서 결과를 확인하면 아래와 같이 Header
component의 경우 리 렌더링이 발생하지 않는 것을 확인 할 수 있습니다.
방법2
두 번째 방법은 별도의 component 안에서 상태 값을 관리하여, App
component의 리 렌더링을 막으며,
하위 component 중 useContext
를 이용하고 있는 component만 리 렌더링시키는 방법입니다.
그럼, 바로 코드를 작성해 보겠습니다.
countContext.tsx
...
export const CountProvider = ({
children,
}: PropsWithChildren) => {
const [count, setCount] = useState(0)
const countIncrement = useCallback(() => {
setCount(count + 1)
},[count])
const countDecrement = useCallback(() => {
setCount(count - 1)
},[count])
return <CountContext.Provider value={{ count, countIncrement, countDecrement }}>{children}</CountContext.Provider>;
};
App.tsx
...
function App() {
return (
<CountProvider>
<Header />
<Main />
<Footer />
</CountProvider>
)
}
...
위 코드를 작성 후 실행해 보면 아래와 같이 useContext
를 이용하고 있는 Main
component 이외의 component가 리 렌더링 되지 않는 것을 확인 할 수 있습니다.
보충
이외에도 공식 문서를 보면 useMemo
를 이용한 방법도 소개하고 있습니다만, 개인적으로 심플 하다고 생각하는 두 가지 방법만 확인해 보았습니다.
관심이 있으시다면 다른 여러 방법을 확인 후 사용하고 싶은 방법을 이용해 보셔도 좋을 듯합니다.
참고자료
react developer tools
react useContext - Optimizing re-renders when passing objects and functions