본문 바로가기

TIL

개인과제 - 포켓몬도감 만들기 ②

■  Context API

Context 는 그 하위에 있는 요소들끼리 공유하는 맥락으로 어디서 사용되는가에 따라 부분적 전역상태로 사용 될 수 있음

* Context !== 전역상태

* 단순한 데이터 전달과 같은 경우 props 사용이 더 적절하다.

 

⚬  createContext : 컨텍스트를 만듦

⚬  Context Provider : 컨텍스트를 원하는 위치에 주입

⚬  useContext : 컨텍스트를 사용

   - 사용할 Context 는 export 가 되어있어야 함!

// createContext
import { createContext } from "react";

// 파스칼케이스(대문자로 작성), 사용할 컨텍스트 export 해줄것!
export const CountContext = createContext();
// Context Provider
// 생성한 컨텍스트에 Provider를 붙여서 사용, 하위 컴포넌트에 전달할 value 추가
return (
    <div>
      <CountContext.Provider value={{ count, setCount }}>
        {count}
        <InputArea />
        <ListArea />
      </CountContext.Provider>
    </div>
  );
};
// useContext
// 자식 컴포넌트에서 useContext hook을 사용하여 Context에 넣은 값에 접근할 수 있다.
import { useContext } from "react";
import { CountContext } from "../App";

const SubInputTagArea = () => {
  // 구조분해할당으로 필요한것만 꺼내서 사용할 수 있음
  // useContext 인자로 사용할 컨텍스트 넣고 import 하기
  const { setCount } = useContext(CountContext);
  return (
    <div>
      <button onClick={() => setCount((prev) => prev + 1)}>증가</button>
    </div>
  );
};

 

 

■  Context API로 리팩터링하기

// Dex.jsx
// PokemonContext 생성
export const PokemonContext = createContext();

⠇

// PokemonContext.Provider 로 하위 컴포넌트를 감싸서 value로 값 전달
return (
    <>
      <PokemonContext.Provider
        value={{ selectedPokemon, removePokemon, addPokemon, MOCK_DATA }}
      >
        <Dashboard />
        <PokemonList />
      </PokemonContext.Provider>
    </>
  );

 

 ⚬ 자식 컴포넌트인 PokemonCard로 props 전달 역할만 하던 PokemonList 컴포넌트

// PokemonList.jsx
const PokemonList = () => {
  return (
    <StListContainer>
      <PokemonCard />
    </StListContainer>
  );

 

 ⚬ Dashboard 와 pokemonCard 컴포넌트에서는 props 로 전달받은 값들 제거 후 useContext(PokemonContext) 로 필요한 값 사용해서 기존 코드를 리팩토링 하였다.

// Dashboard.jsx
const Dashboard = () => {
  const { selectedPokemon, removePokemon } = useContext(PokemonContext);
  const navigate = useNavigate();
  return (
    <StDashboardContainer>
      <h2>My Pokemon</h2>
      <StPokemonContainer>
        {selectedPokemon.map((pokemon) => {
          return (
            <StCard
              key={pokemon.id}
              onClick={() => navigate(`/pokemon-detail?id=${pokemon.id}`)}
            >
              <img src={pokemon.img} alt={`${pokemon.name} 이미지`} />
              <p>{pokemon.name}</p>
              <p>{pokemon.number}</p>
              {pokemon.isSelected ? (
                <StButton
                  onClick={(e) => {
                    e.stopPropagation();
                    removePokemon(pokemon);
                  }}
                >
                  삭제
                </StButton>
              ) : (
                <StButton>추가</StButton>
              )}
            </StCard>
          );
        })}
      </StPokemonContainer>
    </StDashboardContainer>
  );
};
// PokemonCard.jsx
const PokemonCard = () => {
  const { MOCK_DATA, addPokemon } = useContext(PokemonContext);
  const navigate = useNavigate();
  let isSelected = true;
  return (
    <>
      {MOCK_DATA.map((pokemon) => {
        return (
          <StCard
            key={pokemon.id}
            onClick={() => navigate(`/pokemon-detail?id=${pokemon.id}`)}
          >
            <div>
              <img
                src={pokemon.img_url}
                alt={`${pokemon.korean_name} 이미지`}
              />
              <p>{pokemon.korean_name}</p>
              <p>No. {pokemon.id} </p>
            </div>
            {isSelected ? (
              <StButton
                onClick={(e) => {
                  e.stopPropagation();
                  addPokemon(pokemon);
                }}
              >
                추가
              </StButton>
            ) : (
              <StButton>삭제</StButton>
            )}
          </StCard>
        );
      })}
    </>
  );
};

 

 

🤔 느낀점

어제 과제의 전반적인 기능을 만들고 prop drilling을 사용해서 상태관리를 하던 부분을 Context API 로 리팩토링 했다.

강의에서는 조금 간단한 예제를 통해서 학습했었고 내가 직접 과제에 적용할 때는 익숙하지 않아서 어떻게 적용해야할 지 감이 안왔었다.

게다가 이미 내가 작성했던 여러 코드들 때문에 더 복잡하게 느껴졌다.

오늘 실시간 강의와 보충수업에서 한번 더 다루었던 Context API 내용을 토대로 과제에 적용해보았는데 계속 오류가 나서 코드를 쓰고 되돌리기를 여러번 반복했다. 그 과정에서 오류메세지를 하나씩 해결하다보니 더이상 오류가 발생하지 않았다.

혼자 몇시간동안 이리저리 삽질하다보니 사용방법이 이전보다 훨씬 익숙해지게 된 것 같다. 사실 Context를 새로운 파일을 생성해서 사용하고 싶었는데 consumer, {children}... 등 관련 개념부터 이해가 부족해서 우선 배웠던 방법으로 해보았다. 조금 아쉬워서 좀더 공부해서 외부 파일로 Context를 생성해서 사용하는 방법을 연구해봐야겠다.

'TIL' 카테고리의 다른 글

개인과제 - 포켓몬도감 만들기 ④  (0) 2024.08.27
개인과제 - 포켓몬도감 만들기 ③  (0) 2024.08.26
개인과제 - 포켓몬도감 만들기 ①  (2) 2024.08.22
react-router-dom  (0) 2024.08.21
RTK, RRD, Supabase  (0) 2024.08.20