오늘은 그냥 리액트에서 Context를 사용하는 또 다른 방법을 정리해보려고 한다..
Context.Provider 분리하는 이유
유튜브에서 Context관련 글을 검색해 보는데, 다음과 같은 영상이 눈에 들어왔다.
썸네일만 보면 Context 컴포넌트의 Provider 프로퍼티를 쓰지 말고, Comtext.Provider 컴포넌트를 만들어 써라
라는 느낌의 그림이다.
대충 내용만 요약하자면, Context컴포넌트를 따로 모듈로 분리해서 사용해라인데,
그 이유는 일반적으로 상위 컴포넌트에서 하위 컴포넌트들에게 데이터를 전달하기 위해 <Context.Provider>를 쓰면
state가 변경되면서 useContext로 데이터를 받지 않는 다른 자식컴포넌트 즉, 모든 컴포넌트가 리랜더링 되니
성능상 좋지 않다. 라는 내용이었다..
위 영상을 포함해서 gpt4 친구에게 물어보니 다음과 같은 이유를 들었다.
1. 하위 컴포넌트들이 모두 리랜더링 되며 성능에 문제가 생길 가능성이 있음
2. 모듈 단위로 분리하여 가독성과 유지보수성을 높임
3. 동일한 로직을 가지는 컴포넌트에서 Provider 컴포넌트를 재사용할 수 있음.
4. 코드의 간결화...
곰곰히 생각해보면 대충 다 맞는 말 같다..
아래 샘플코드를 보도록 하자.
샘플코드
import { createContext, useState, useContext } from "react";
const NewContextProvider = createContext();
const App = () => {
const [count, setCount] = useState(1);
const increase = () => {
setCount((count) => count + 1);
};
return (
<>
<div className="App">
<NewContextProvider.Provider value={{ count, setCount, increase }}>
<Child1 />
<Child2 />
<Child3 />
</NewContextProvider.Provider>
</div>
</>
);
};
const Child1 = () => {
console.log("Child1이 리랜더링 됨");
const { count, setCount, increase } = useContext(NewContextProvider);
return (
<>
Child1 컴포넌트입니다.. 👉<button onClick={increase}>+</button> 👉 값:
{count}
<br></br>
</>
);
};
const Child2 = () => {
console.log("Child2이 리랜더링 됨");
return (
<>
Child2 컴포넌트입니다.. 👉<button>+</button> 👉 값: <br></br>
</>
);
};
const Child3 = () => {
console.log("Child3이 리랜더링 됨");
return (
<>
Child3 컴포넌트입니다.. 👉<button>+</button> 👉 값:
</>
);
};
export default App;
결과
보면 useContext를 통해 state를 사용하는 자식컴포넌트는 Child1뿐이지만, Child2와 Child3까지 리랜더링 되는 걸
확인할 수 있다..
당연한 이야기이지만, state가 변경되며 부모 컴포넌트인 App 컴포넌트가 리랜더링 되며, 자식 컴포넌트들이
모두 리랜더링 된다.
이런 문제를 방지하기 위해 Context 로직을 분리하는 방법이 있다.
Context.Provider 컴포넌트로 분리하는 방법
그냥 코드만 보면서 이야기 하도록 하겠다..
App.jsx
import { createContext, useState, useContext } from "react";
import {
NewContextProvider,
CountContext,
GetCountContext,
} from "./context/NewContext.jsx";
const App = () => {
return (
<>
<div className="App">
<NewContextProvider>
<Child1 />
<Child2 />
<Child3 />
</NewContextProvider>
</div>
</>
);
};
const Child1 = () => {
console.log("Child1이 리랜더링 됨");
const { count, setCount, increase } = useContext(NewContextProvider);
return (
<>
Child1 컴포넌트입니다.. 👉<button onClick={increase}>+</button> 👉 값:{" "}
{count}
<br></br>
</>
);
};
const Child2 = () => {
console.log("Child2이 리랜더링 됨");
return (
<>
Child2 컴포넌트입니다.. 👉<button>+</button> 👉 값: <br></br>
</>
);
};
const Child3 = () => {
console.log("Child3이 리랜더링 됨");
return (
<>
Child3 컴포넌트입니다.. 👉<button>+</button> 👉 값:
</>
);
};
export default App;
NewContext.jsx
import { createContext, useContext, useState } from "react";
export const CountContext = createContext();
export const NewContextProvider = ({ children }) => {
const [count, setCount] = useState(1);
console.log(children);
const increase = () => {
setCount((count) => count + 1);
};
return (
<CountContext.Provider value={{ count, setCount, increase }}>
{children}
</CountContext.Provider>
);
};
export const GetCountContext = () => useContext(CountContext);
결과
위 같이 Context.Provider를 따로 컴포넌트(모듈)로 분리해서 사용하니 useContext를 통해
data를 사용하는 자식 컴포넌트(Child1)만 리랜더링 되는 결과물을 볼 수 있다..
그래서 성능을 고려해서 가능하면 Context를 이렇게 분리하여 사용하든, Provider 라이브러리를 사용해서
개발하는 것도 또 하나의 방법 같다..
# 참조 링크
https://www.youtube.com/watch?v=16yMmAJSGek
'FrontEnd > React' 카테고리의 다른 글
[React] 동적 라우팅에 대한 설명 및 리액트에서의 동적 라우팅 사용방법 (1) | 2024.04.28 |
---|---|
[React] 리액트 : 페이지 라우팅(라우트)에 대한 정리 및 라우팅 설정 방법 (0) | 2024.04.22 |
[React] 리액트 컴포넌트간 데이터 전달 : Context 훅에 대한 정리 (feat. createContext + useContext) (0) | 2024.04.20 |
[React] 리액트 상태 관리: 함수형 업데이트에 대한 정리 (0) | 2024.04.13 |
[React] React에서의 최적화 1: react.memo 정리 (feat. 리랜더링 방지) (0) | 2024.04.12 |