Context 알아보기

2025. 4. 22. 16:23·React

Context란?

Context는
여러 컴포넌트가 공통으로 사용하는 값을
컴포넌트 트리 어디서든 쉽게 접근할 수 있도록 만들어주는 전역 데이터 저장소


왜 Context를 써야 할까?

리액트 애플리케이션에서는 데이터 전달이 기본적으로 부모 → 자식 props 방식
여러 컴포넌트에서 공통으로 필요한 데이터를 매번 props로 전달하면 코드가 지저분해지는 props drilling 발생!!


Context 패턴 정석 구성

  1. store에서 context 선언
  2. Provider로 컴포넌트 트리를 감싸서 전역 값 전달
  3. 커스텀 훅으로 context 값 가져오기

Next.js + TypeScript 이용한 Context 정리

타입(interface) 선언하기

=> 컨텍스트로 관리할 상태와 그 상태를 변경할 함수의 타입을 정의

interface ColorContextType {
  color: string;
  subcolor: string;
  changeColor: (color: string) => void;
  changeSubcolor: (subcolor: string) => void;
}

 

store /

- context 선언

import { createContext } from "react";

const ColorContext = createContext<ColorContextType | undefined>(undefined);

 

  • createContext()를 통해 Context 생성.
  • 초기값을 undefined로 두는 이유: Provider 없이 context를 사용했을 때 예외처리를 위함

- Provider 컴포넌트 만들기

import { useState, ReactNode } from "react";

export const ColorProvider = ({ children }: { children: ReactNode }) => {
  const [color, setColor] = useState<string>("black");
  const [subcolor, setSubcolor] = useState<string>("red");

  const changeColor = (c: string) => setColor(c);
  const changeSubcolor = (c: string) => setSubcolor(c);

  return (
    <ColorContext.Provider value={{ color, subcolor, changeColor, changeSubcolor }}>
      {children}
    </ColorContext.Provider>
  );
};

 

 

  • 상태(state)와 상태를 변경하는 함수 선언
  • Context의 value로 넘겨주기
  • children은 ReactNode 타입으로 받기 (타입스크립트 환경에서 필수)
  • 감싸진 컴포넌트들에 context 값을 공급하기 위해 children 사용

- 커스텀 훅으로 Context 값 가져오기

import { useContext } from "react";

export const useColorContext = () => {
  const context = useContext(ColorContext);
  if (!context) {
    throw new Error("useColorContext must be used within a ColorProvider");
  }
  return context;
};

 

 

  • useContext()로 context 값을 가져옴.
  • 값이 없으면 (즉, Provider로 감싸지 않았으면) 에러 발생.
  • 가져올때마다 에러처리 하지 않아도 바로 이용 가능!!!

실제 사용 예시

<ColorProvider>
  <App />
</ColorProvider>

 

 

const { color, changeColor } = useColorContext();

=> App 내부 어디서든 사용 가능

 

1 타입 선언 interface
2 Context 생성 createContext()
3 Provider 생성 ColorProvider
4 커스텀 훅 useColorContext()

 

 

실전_북마크 예제 작성

: 도서 목록에서 북마크 클릭 시 도서 저장 및 / 삭제 / 완전 삭제 기능까지 구현

 

북마크 구성요소 정리

store/book-mark.ts 북마크 전역 상태 관리 (context + provider + hook)
components/book_mark/BookMarkItem.tsx 북마크 목록 테이블의 단일 행 컴포넌트 / 재사용 가능한 UI 컴포넌트 모음
app/book_mark/page.tsx 북마크 목록 페이지 (목록 + 전체 삭제 버튼)
app/book_mark/layout.tsx 북마크 페이지 전용 레이아웃
utils/http-commons.ts axios 기본 인스턴스 설정

 

types/book.ts

export interface Book {
  isbn: string;
  title: string;
  author: string;
  price: number;
  img: string;
}

=> 북마크에 사용할 도서 데이터 타입 정의

 

store/book-mark.ts

"use client";

import { createContext, useContext, useState, useMemo, ReactNode, useCallback } from "react";
import { Book } from "@/types/book";

// context value 타입
interface BookMarkContextType {
  bookMark: Book[];
  registBookMark: (book: Book) => void;
  removeBookMark: (isbn: string) => void;
  clearBookMark: () => void;
}

// context 생성
const BookMarkContext = createContext<BookMarkContextType | undefined>(undefined);

// Provider 컴포넌트
export const BookMarkProvider = ({ children }: { children: ReactNode }) => {
  const [bookMark, setBookMark] = useState<Book[]>([]);

  const registBookMark = useCallback((book: Book) => {
    setBookMark((prev) => (prev.find((item) => item.isbn === book.isbn) ? prev : [...prev, book]));
  }, []);

  const removeBookMark = useCallback((isbn: string) => {
    setBookMark((prev) => prev.filter((item) => item.isbn !== isbn));
  }, []);

  const clearBookMark = useCallback(() => {
    setBookMark([]);
  }, []);

  // value를 useMemo로 캐싱해 리렌더 최적화
  const value = useMemo(
    () => ({ bookMark, registBookMark, removeBookMark, clearBookMark }),
    [bookMark]
  );

  return <BookMarkContext.Provider value={value}>{children}</BookMarkContext.Provider>;
};
//커스텀 훅
export const useBookMarkContext = () => {
  const context = useContext(BookMarkContext);
  if (!context) {
    throw new Error("useBookMarkContext must be used within a BookMarkProvider");
  }
  return context;
};
  • 전역 상태를 context로 관리
  • useMemo로 value 캐싱해 리렌더 최적화
  • useCallback으로 함수 재생성 방지
  • 커스텀 훅으로 에러 메시지와 context 가져오기 통일
   커스텀 훅의 장점
  • 매번 useContext + 에러처리 중복 안 해도 됨
  • context 구조 변경되면 이 훅만 수정하면 됨
  • 에러 메시지 일관성 유지

layout.tsx에서 Provider로 감싸기

전역 상태를 사용하려면 context provider로 컴포넌트 트리를 감싸야 함
import { BookMarkProvider } from "@/store/book-mark";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      <body>
        <BookMarkProvider>
          {children}
        </BookMarkProvider>
      </body>
    </html>
  );
}

 

=> 이렇게 감싸주면 하위 페이지에서 useBookMarkContext()로 북마크 목록을 사용

 

북마크 목록 페이지

"use client";

import { useBookMarkContext } from "@/store/book-mark";
import BookMarkItem from "@/components/book_mark/BookMarkItem";
import styles from "./book_mark.module.scss";

// 북마크 목록 페이지 컴포넌트
export default function BookMarkPage() {
  // context에서 북마크 목록과 전체 삭제 함수 가져오기
  const { bookMark, clearBookMark } = useBookMarkContext();

  return (
    <div className={styles.bookList}>
      {/* 전체 삭제 버튼 */}
      <button onClick={clearBookMark}>모두 삭제</button>

      {/* 도서 목록 테이블 */}
      <table>
        <thead>
          <tr>
            <th>이미지</th>
            <th>번호</th>
            <th>제목</th>
            <th>저자</th>
            <th>가격</th>
            <th>비고</th>
          </tr>
        </thead>
        <tbody>
          {/* 북마크 목록 있을 때 */}
          {bookMark.length > 0 ? (
            bookMark.map((book) => (
              <BookMarkItem key={book.isbn} book={book} />
            ))
          ) : (
            // 북마크 없을 때 안내 메시지
            <tr>
              <td colSpan={6}>북마크 없음</td>
            </tr>
          )}
        </tbody>
      </table>
    </div>
  );
}

 

 

useBookMarkContext() 북마크 목록과 삭제 함수 가져옴
clearBookMark() 전체 삭제 버튼 클릭 시 호출
bookMark.map() 북마크 목록을 map 을 통하여 테이블로 출력
북마크 없을 때 안내 메시지 출력
스타일 SCSS 모듈로 적용

 

'React' 카테고리의 다른 글

타입스크립트 사용법과 기본 타입 정리  (0) 2025.05.26
React Context API와 LocalStorage로 상태 관리  (0) 2025.04.23
TanStack Query (React Query) 알아보기  (0) 2025.04.21
Axios와 async/await  (2) 2025.04.16
React & Next.js 활용해보기 / CSR vs SSR  (1) 2025.04.14
'React' 카테고리의 다른 글
  • 타입스크립트 사용법과 기본 타입 정리
  • React Context API와 LocalStorage로 상태 관리
  • TanStack Query (React Query) 알아보기
  • Axios와 async/await
startfront
startfront
startfront 님의 블로그 입니다.
  • startfront
    startfront 님의 블로그
    startfront
  • 전체
    오늘
    어제
    • 분류 전체보기 (42)
      • 프로젝트 (5)
        • 프로젝트 해보기 (1)
        • 디자인 알아보기 (2)
        • 프로젝트의 기본 (2)
      • 백엔드의 이해 (4)
      • React (14)
      • 프론트엔드 기본 (2)
        • Html (1)
        • Css (0)
        • JavaScript (1)
      • Cs기본지식 (14)
        • 알고리즘 (8)
        • 데이터베이스 (6)
      • Java (3)
        • Java의 이해 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
startfront
Context 알아보기
상단으로

티스토리툴바