next.js app router에서 context api를 사용하는 법은 typescript와 같이 소개한다.
import React, { createContext, useContext, useState, ReactNode } from 'react';
interface MyContextType {
data: string;
setData: React.Dispatch<React.SetStateAction<string>>;
}
const MyContext = createContext<MyContextType | undefined>(undefined);
export const MyProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [data, setData] = useState<string>('초기값'); // 기본값 설정
return (
<MyContext.Provider value={{ data, setData }}>
{children}
</MyContext.Provider>
);
};
export const useMyContext = (): MyContextType => {
const context = useContext(MyContext);
if (!context) {
throw new Error('useMyContext는 MyProvider 내부에서 사용되어야 합니다.');
}
return context;
};
interface MyContextType {
data: string;
setData: React.Dispatch<React.SetStateAction<string>>;
}
React.Dispatch<React.SetStateAction<string>>;
- React.Dispatch는 인자로 React.SetStateAction<string>를 받는다.
useState의 setter함수에 사용하는 함수로 ts에서 useState 자체에서는 setter 함수의 타입을 자동으로 추론하기 때문에 별도로 타입을 명시하지 않아도 작동하지만 context에서는 명시하는 것을 추천
const MyContext = createContext<MyContextType | undefined>(undefined);
createContext:
React의 createContext 함수를 사용하여 Context 객체를 생성합니다.
초기값:
초기값으로 undefined를 지정함으로써, 만약 Provider 없이 Context를 사용하려고 하면 에러를 발생시킬 수 있도록 설계되었습니다.
export const MyProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [data, setData] = useState<string>('초기값'); // 기본값 설정
return (
<MyContext.Provider value={{ data, setData }}>
{children}
</MyContext.Provider>
);
};
상태 관리:
useState 훅을 사용해 data라는 상태와 이를 업데이트하는 setData 함수를 생성합니다. 초기값은 '초기값'으로 설정되어 있습니다.
Provider 역할:
생성된 MyContext.Provider에 { data, setData }를 값으로 전달하여, 이 Provider 하위의 모든 컴포넌트가 해당 상태와 업데이트 함수를 사용할 수 있게 만듭니다.
Next.js 앱 라우터와의 통합:
Next.js의 새로운 App Router 구조에서는 이 Provider를 최상위 레이아웃 파일에 래핑하여 페이지 전체에서 전역 상태에 접근할 수 있도록 합니다.
export const useMyContext = (): MyContextType => {
const context = useContext(MyContext);
if (!context) {
throw new Error('useMyContext는 MyProvider 내부에서 사용되어야 합니다.');
}
return context;
};
useContext 사용:
React의 useContext 훅을 사용해 현재 Context 값을 가져옵니다.
안전성 체크:
만약 Provider 밖에서 이 훅을 호출할 경우 context가 undefined가 되므로, 이를 감지하고 명확한 에러 메시지를 던져 개발자가 올바르게 Provider 내부에서 사용하도록 유도합니다.
편의성:
이 커스텀 훅을 사용하면 각 컴포넌트에서 useContext(MyContext)를 직접 호출할 필요 없이, 간단히 useMyContext()로 Context 값에 접근할 수 있습니다.
리액트, 페이지 라우트 next.js는 가장 상위 파일인 app.tsx에 적용하지만 app router는 가장 상위 layout.tsx에 적용한다.
import './globals.css';
import { MyProvider } from '../contexts/MyContext';
export const metadata = {
title: 'My Next.js App',
description: 'App Router에서 Context API 사용 예시',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ko">
<body>
{/* 앱 전체에 MyProvider 적용 */}
<MyProvider>
{children}
</MyProvider>
</body>
</html>
);
}
MyProvider를 불러와 상위 구조에 감싼다.
'use client';
import React from 'react';
import { useMyContext } from '../../contexts/MyContext';
import Link from 'next/link';
export default function SavePage() {
const { setData } = useMyContext();
const handleSave = () => {
// 원하는 데이터를 저장(업데이트)합니다.
setData('저장된 데이터입니다!');
};
return (
<div>
<h1>데이터 저장 페이지</h1>
<button onClick={handleSave}>데이터 저장</button>
<p>
<Link href="/read">데이터 조회 페이지로 이동</Link>
</p>
</div>
);
}
useMyContext를 사용하여 setData 함수를 가져온다.
setData 함수에 저장할 함수를 만들고 함수를 적용하면 저장된다.
// app/read/page.tsx
'use client';
import React from 'react';
import { useMyContext } from '../../contexts/MyContext';
import Link from 'next/link';
export default function ReadPage() {
const { data } = useMyContext();
return (
<div>
<h1>데이터 조회 페이지</h1>
<p>저장된 데이터: {data}</p>
<p>
<Link href="/save">데이터 저장 페이지로 이동</Link>
</p>
</div>
);
}
useMyContext를 가져와 data를 불러온다.
불러온 data를 원하는 곳에서 사용한다.