router.tsx

const withErrorAndSuspenseBoundary = (element: React.ReactNode) => ({
element: (
<ErrorBoundary fallback={<ErrorArea />}>
<Suspense fallback={<LoadingArea />}>{element}</Suspense>
</ErrorBoundary>
),
});

React에서 Provider는 공통으로 사용되는 데이터를 전역 상태처럼 관리하고, 필요한 컴포넌트에 쉽게 공급하는 역할을 한다.
쉽게 말하면, React에서의 물류센터 같은 존재입니다. 어떤 데이터든 이 센터에 넣어두면, 아래에 있는 어떤 컴포넌트든 필요할 때 가져다 쓸 수 있다.
여러 컴포넌트가 같은 데이터를 필요로 하는 상황을 상상해볼게요. 예를 들어, 사용자 정보가 있다면 이건 헤더, 사이드바, 댓글, 대시보드에서도 필요하겠지?
<App user={user}>
<Header user={user}>
<Nav user={user}>
<Profile user={user} />
</Nav>
</Header>
</App>
이렇게 props를 계속 넘겨야 해요. 이것을 Prop Drilling이라고 부릅니다. 택배 기사가 1층에서 출발해 꼭대기까지 계단으로 올라가서 직접 배달하는 상황이라고 보면 돼요.
<UserContext.Provider value={user}>
<App />
</UserContext.Provider>
이제 Header, Nav, Profile 어디서든 useContext(UserContext)만 쓰면 데이터를 바로 쓸 수 있어요. 마치 1층에 물류센터를 두고 필요한 사람이 와서 직접 가져가는 구조죠.
src/
└── pages/
└── inquiries/
└── pages/
└── indexes/
└── pages/
└── MessagePage/
├── MessagePage.tsx
└── components/
├── MessageAllGetProvider/
│ └── MessageAllGetProvider.tsx
├── MessageLocalValueProvider/
│ └── MessageLocalValueProvider.tsx
const MessagePage = () => {
return (
<MessageAllGetProvider>
<MessageLocalValueProvider>
<MessageLayout
MessageTable={<MessageTableBox />}
MessageDatePicker={<MessageDatePicker />}
// ...
/>
</MessageLocalValueProvider>
</MessageAllGetProvider>
);
};
MessageAllGetProvider: 서버에서 데이터 조회MessageLocalValueProvider: 로컬 상태 관리 (ex. 날짜 선택)const MessageAllGetProvider = ({ children }) => {
const { company, site } = useCompanySelectProvider();
const [pagination, setPagination] = useState({ page: 1, size: 20, total: 0 });
const [dateRange, setDateRange] = useState();
const [selectedSite, setSelectedSite] = useState(company.siteUrls[0]);
const { isFetching, data } = useInquiryAllGetQuery({
path: { companyId: company?.uuid },
query: { pagination, siteUrl: selectedSite, dateRange },
body: {},
});
const changePagination = (newPage) => setPagination(newPage);
const changeSite = (site) => setSelectedSite(site);
return (
<MessageAllGetContext.Provider
value={{
changePagination,
pagination,
selectedSite,
changeSite,
dateRange,
setDateRange,
inquiries: data?.inquiries || [],
}}
>
{children}
{isFetching && <LoadingOverlay />}
</MessageAllGetContext.Provider>
);
};
const MessageTableBox = () => {
const { inquiries, changePagination } = useMessageAllGetProvider();
return (
<Table>
{inquiries.map((inquiry) => (
<Row key={inquiry.id}>{inquiry.title}</Row>
))}
</Table>
);
};
const CustomApiSettingUpdateContext = createContext({
uuid: '',
setUuid: () => {},
name: '',
status: '',
media: '',
apiMedias: [],
handleNameInputChange: () => {},
handleStatusItemClick: () => {},
handleMediaItemClick: () => {},
handleSubmitButtonClick: () => {},
handleCancelButtonClick: () => {},
});
이걸 사용하는 컴포넌트는 다음과 같아요:
const {
name,
handleNameInputChange,
handleSubmitButtonClick
} = useCustomApiSettingUpdateProvider();
return (
<>
<Input value={name} onChange={handleNameInputChange} />
<Button onClick={handleSubmitButtonClick}>등록</Button>
</>
);
| 구분 | 역할 |
|---|---|
createContext() | 데이터를 전역처럼 사용할 수 있게 ‘컨텍스트’를 만듦 |
Context.Provider | 데이터를 하위 컴포넌트에 전달하는 ‘공급자 역할’ |
useContext() | 하위 컴포넌트에서 Context에 접근하는 훅 |
| Provider 컴포넌트 | 실제로 값을 정의하고 상태를 관리하는 컴포넌트 |
| 장점 | Prop drilling 방지, 유지보수 쉬움, 관심사 분리, 재사용성 ↑ |
Provider는 React에서 공통 데이터나 상태를 효율적으로 관리할 수 있게 도와주는 핵심 개념이다.
특히 복잡한 페이지일수록, 여러 상태와 데이터를 여러 컴포넌트에 전달할 일이 많을수록 Provider 패턴은 필수라고 할 수 있다.
이 구조를 이해하고 나면, 협업이나 유지보수에서도 훨씬 수월해질 거다.
복잡한 상태 로직, 중첩된 데이터 전달로 고생하고 있다면, 꼭 Provider 패턴을 적극적으로 활용해보자! 💪