[React] Context API
Context API가 뭐고 어떻게 사용할까?
React
Context API
Props Drilling 문제 해결 방법 중 하나
컴포넌트 트리 전반에 걸쳐 데이터를 효율적으로 공유할 수 있게 해주는 기능이다.
Context를 사용하면, 데이터를 필요로 하는 컴포넌트가 트리 구조상 어디에 있든 상관없이 Provider로부터 직접 데이터에 접근할 수 있다.
Context API 핵심 구성 요소
createContext: 컨텍스트 객체 생성Context.Provider: 생성된 컨텍스트를 하위 컴포넌트들에게 제공(Provide),valueprop을 통해 공유할 데이터를 전달useContext:Provider가 제공한 데이터에 접근(Consume)하는 훅
사용법
1. Context 생성
import type { AccommodationType } from '@/types/accommodationType';
import { createContext } from 'react';
const AccommodationContext = createContext<AccommodationType | null>(null);
export const AccommodationProvider = AccommodationContext.Provider;
export default AccommodationContext;
createContext를 사용해 컨텍스트 객체를 생성한다.
import AccommodationContext from '@/features/search/contexts/AccommodationContext';
import { useContext } from 'react';
const useAccommodation = () => {
const context = useContext(AccommodationContext);
if (!context) {
throw new Error(
'useAccommodation은 AccommodationProvider 내에서만 사용 가능',
);
}
return context;
};
export default useAccommodation;
이때 커스텀 훅을 함께 만들어두면, 컨텍스트를 사용할 때마다 발생하는 특정 반복 작업을 줄이고 코드를 깔끔하게 유지할 수 있다.
여기서는 훅이 프로바이더 내부에서만 사용되도록 했다. (context === null인 경우)
2. Provider로 감싸기
const AccommodationList = ({
accommodations,
}: {
accommodations: AccommodationResponse;
}) => {
return (
<AccommodationListContainer>
{accommodations?.map((item: AccommodationType) => (
<AccommodationProvider key={item.accommodation_id} value={item}>
<Accommodation />
</AccommodationProvider>
))}
<Divider width="100%" />
</AccommodationListContainer>
);
};
데이터 공유가 필요한 컴포넌트 트리의 최상단에서 Provider 컴포넌트로 하위 컴포넌트들을 감싸준다.
3. 데이터 사용
const Accommodation = () => {
const accommodation = useAccommodation();
return (
<AccommodationContainer>
<AccommodationImg src={accommodation.accommodation_photo_url} />
<AccommodationInfo />
</AccommodationContainer>
);
};
위에서 구현한 커스텀 훅으로 데이터에 바로 접근할 수 있다.
Context API의 부작용
불필요한 리렌더링
Provider의valueprop이 변경되면, 해당 컨텍스트를useContext로 구독(사용)하고 있는 모든 하위 컴포넌트가 리렌더링된다.valueprop에 매번 새로운 객체를 전달하면, 부모 컴포넌트가 리렌더링될 때마다value가 새롭게 인식되어 컨텍스트를 사용하는 모든 자식이 리렌더링된다.
해결책 (최적화)
useMemo/useCallback:value로 전달되는 객체나 함수를useMemo와useCallback으로 메모이제이션하여 불필요한 재생성을 방지한다.- 컨텍스트 분리: 하나의 거대한 컨텍스트에 모든 전역 상태를 넣지 말자.
- 상태가 자주 변경되는 부분과 거의 변경되지 않는 부분은 별도의 컨텍스트로 분리한다.