TroubleShooting
[포켓몬 도감] - Context API로 바꾸기
집으로 감자
2025. 2. 4. 11:43
문제 상황
요구 사항
props drilling으로 작성한 포켓몬 도감 코드를 Context API로 변환하세요
다음 요구사항을 만족하기 위해서는 useContext 훅을 사용해야했다.
useContext를 이용해서 state를 전역에서 관리하는 것을 배우긴 했지만,
🚨 함수를 전역에서 관리하는 것을 알지는 못했다.
검색을 통해 Provider을 새로 만들어 줄 수 있는 방법이 있다는 것을 알게 됐다.
해결 과정
Provider 새로 만드는 방법
import { createContext } from 'react';
const CounterContext = createContext();
function CounterProvider({ children }) {
return <CounterContext.Provider>{children}</CounterContext.Provider>;
}
function App() {
return (
<CounterProvider>
<div>
<Value />
<Buttons />
</div>
</CounterProvider>
);
}
다음과 같은 구조로 Provider을 새로 만들 수 있다.
✅ 여기 안에서 state와 함수를 관리하면 된다.
import { createContext } from 'react';
const CounterContext = createContext();
function CounterProvider({ children }) {
const value = {name, age}
return <CounterContext.Provider value={value}>{children}</CounterContext.Provider>;
}
function App() {
return (
<CounterProvider>
<div>
<Value />
<Buttons />
</div>
</CounterProvider>
);
}
Provider 안에 미리 value를 전달할 수도 있다.
포켓몬 도감에 Provider 적용하기
01 PokemonContext 생성
import { createContext, useEffect, useState } from "react";
export const PokemonContext = createContext(null);
export const PokemonProvider = ({ children }) => {};
createContext를 이용해서 PokemonContext를 생성한다.
PokemonProvider 함수를 선언한 뒤, 인자로 children을 전달한다.
02 전역에서 관리할 state와 함수 코드 작성
import { createContext, useEffect, useState } from "react";
export const PokemonContext = createContext(null);
export const PokemonProvider = ({ children }) => {
const [pokemonList, setPokemonList] = useState(
JSON.parse(localStorage.getItem("pokemonList")) || []
);
/** 로컬 스토리지 저장 */
useEffect(() => {
localStorage.setItem("pokemonList", JSON.stringify(pokemonList));
}, [pokemonList]);
const addPokemon = (id, img_url, korean_name, types) => {
/** 예외상황01: 이미 등록된 포켓몬일 때 */
if (pokemonList.some((pokemon) => pokemon.id === id)) {
alert("이미 등록된 포켓몬입니다");
return;
}
/** 예외상황02: 포켓몬 6마리 모두 등록됐을 때 */
if (pokemonList.length > 5) {
alert("포켓몬 6마리를 모두 등록하셨습니다");
return;
}
setPokemonList((prev) => {
return [...prev, { id, img_url, korean_name, types }];
});
};
const removePokemon = (id) => {
setPokemonList((prev) => prev.filter((pokemon) => pokemon.id !== id));
};
};
내부에는 기존에 작성했던
사용자가 선택한 6마리의 포켓몬 배열의 state
포켓몬 카드 추가 함수 addPokemon
포켓몬 카드 삭제 함수 removePokemon
코드를 넣어준다.
03 Provider 컴포넌트 반환하기
const value = {
pokemonList,
addPokemon,
removePokemon,
};
return (
<PokemonContext.Provider value={value}>{children}</PokemonContext.Provider>
);
마지막으로 Provider에 전달할 value를 미리 작성한 뒤에
Provider 컴포넌트를 반환하면 된다.
04 Dex.jsx에 Provider 적용하기
import React, { useEffect, useState } from "react";
import Dashboard from "../components/Dashboard";
import styled from "styled-components";
import PokemonList from "../components/PokemonList";
import Header from "../components/Header";
import { PokemonProvider } from "../context/PokemonContext";
const Dex = () => {
/** UI */
return (
<PokemonProvider>
<Div>
<Header />
<Container>
<Dashboard />
<PokemonList />
</Container>
</Div>
</PokemonProvider>
);
};
export default Dex;
가장 바깥쪽에 <PokemProvider>으로 감싸주면 끝이다.
💻 전체 코드
import { createContext, useEffect, useState } from "react";
export const PokemonContext = createContext(null);
export const PokemonProvider = ({ children }) => {
const [pokemonList, setPokemonList] = useState(
JSON.parse(localStorage.getItem("pokemonList")) || []
);
/** 로컬 스토리지 저장 */
useEffect(() => {
localStorage.setItem("pokemonList", JSON.stringify(pokemonList));
}, [pokemonList]);
/**
* 포켓몬 카드 추가 함수
* @param {*} id
* @param {*} img_url
* @param {*} korean_name
* @param {*} types
*/
const addPokemon = (id, img_url, korean_name, types) => {
/** 예외상황01: 이미 등록된 포켓몬일 때 */
if (pokemonList.some((pokemon) => pokemon.id === id)) {
alert("이미 등록된 포켓몬입니다");
return;
}
/** 예외상황02: 포켓몬 6마리 모두 등록됐을 때 */
if (pokemonList.length > 5) {
alert("포켓몬 6마리를 모두 등록하셨습니다");
return;
}
setPokemonList((prev) => {
return [...prev, { id, img_url, korean_name, types }];
});
};
/**
* 포켓몬 카드 삭제 함수
* @param {*} id
*/
const removePokemon = (id) => {
setPokemonList((prev) => prev.filter((pokemon) => pokemon.id !== id));
};
const value = {
pokemonList,
addPokemon,
removePokemon,
};
return (
<PokemonContext.Provider value={value}>{children}</PokemonContext.Provider>
);
};
결과
context API를 이용해서 코드를 변경해도 잘 작동하는 것을 확인할 수 있다.
context API를 이용해서 state와 함수를 한곳에서 관리하니 나머지 코드들이 간결해졌다.
변수나 로직을 수정하려고 할 때 모든 파일을 돌아다니면서 수정할 필요가 없어서 굉장히 편하다.
[참고자료]
https://velog.io/@velopert/react-context-tutorial
반응형