프로젝트 도중 컴포넌트에게 props를 사용하지 않고 필요한 데이터(state)를 쉽게 공유할 수 있는 방법을 찾던 중 React의 내장 API인 Context API를 사용하게 되어 관련된 정보 정리 해보았다.
Context API를 사용해야 하는 상황
동일한 데이터를 props를 통해 여러 컴포넌트를 거쳐야 하거나 다수의 컴포넌트에서 동일한 데이터가 필요한 경우에는 계속 props를 사용하여 넘겨 줘야되기 때문에 prop drilling(중첩된 여러 계층의 컴포넌트들에게 props를 전달하는 것) 이 발생한다.
⇒ Context API를 이용하면 전역적으로 데이터를 다룰 수 있어 컴포넌트의 깊이 여부와 무관하게 데이터가 필요한 컴포넌트에서만 불러다가 사용할 수 있다. Context API에서 State값을 변경하면, Provider로 감싼 모든 자식 컴포넌트들이 리렌더링되므로 전역 상태 관리를 위한 도구(=Redux, zustand)가 아닌, 데이터를 쉽게 전달하고 공유하기 위한 목적으로 사용하는 것이 적합하다. 그래서 자주 업데이트할 필요가 없는 데이터에 사용되기 때문에 주로 테마(라이트, 다크), 언어, 사용자 데이터 등에 사용된다.
Context API 사용법 in Next.js 13
Context 생성 코드
필자는 createContextd의 value를 관리하기 쉽게 컴포넌트로 분리 후 _app.tsx에 import해 사용했다.
import { DataObject } from "@/InterfaceGather"; import { useSession } from "next-auth/react"; import { createContext, useEffect, useState } from "react"; export const GlobalDataContext = createContext(undefined); export default function GlobalProvider({ children }: any) { const [data, setData] = useState<DataObject[]>([]); useEffect(() => { const fetchData = async (region: string) => { try { const response = await fetch(`/api/...`); const result = await response.json(); setData(result); } catch (error) { console.error("Error:", error); } }; if (region) { fetchData (region); } }, [region]); return ( <GlobalDataContext.Provider value={data}> {children} </GlobalDataContext.Provider> ); }
GlobalProvider로 감싸진 컴포넌트 내에서 value값을 전역으로 사용할 수 있게 된다.
//_app.tsx import React, { useEffect } from "react"; import type { AppProps } from "next/app"; import type { NextComponentType } from "next"; import GlobalProvider from "@/components/GlobalProvider"; export default function App({ Component, pageProps: { session, ...pageProps }, ...appProps }: CustomAppProps) { //.. return ( <> //.. <GlobalProvider> <LayoutComponent> <Global styles={[reset, SCoreDreamFont]} /> <Component {...pageProps} /> </LayoutComponent> </GlobalProvider> //.. </> ); }
Context 접근 코드
import { useContext } from "react"; import { GlobalDataContext } from "@/components/GlobalDataContext"; const SomeComponent = () => { const { data }= useContext(GlobalDataContext); if (!data) { throw new Error("GlobalDataContext must be used within a GlobalProvider"); } return ( <div> {/* data를 사용하여 UI를 구성 */} </div> ); };