til

리액트 숙련 4일 차 @개인과제 100%

fpzmfks 2024. 8. 22. 16:30

오늘은 이전에 props drilling 방식으로 만든 개인과제 결과물을 context API를 이용하여 리팩토링을 하여서 개인과제를 완성하였다. 

 

context API를 사용한 결과 props를 사용하는 빈도가 크게 줄었고, 원하는 곳에서만 원하는 값을 불러올 수 있게 했다. 그리고 또 하나, 이전에는 특정한 위치에서만 작동하도록 작성한 추가/삭제 함수 또한 리팩토링 하여서 함수가 상위 컴포넌트로 올라와 있어도 작동할 수 있도록 하였다. 때문에 명시적으로 전달해야되는 값의 양이 줄어서 코드가 보다 깔끔해질 수 있었다. 

 

아래는 삭제 함수 리팩토링이다. 추가 함수는 너무 길어서 생략했다. 

//기존 삭제 함수
const deleteData = poke.filter((list) => {
    return !(list.id === data.id);
  });
  const deleteBtn = (event) => {
    event.stopPropagation();
    setPoke(deleteData);
};
  

//개선한 삭제 함수
const deleteBtn = (event) => {
    event.stopPropagation();

    const deleteData = poke.filter((list) => {
      return !(list.id === Number(event.target.value));
    });
    setPoke(deleteData);
};

 

이렇게 리팩토링을 해보니 전달해야하는 값이 적은데다가 원할 때에만 조금씩 불러쓸 수 있으니 좋았다. 다만 context API는 여기서 더 확장하여 사용할 수 있는데, 바로 컨텍스트 파일에서 컴포넌트를 커스텀하여 사용하는 것이다. 컨텍스트 파일에서 컴포넌트를 커스텀하여 사용하면 코드가 더 깔끔해진다. 

 

커스텀 컨텍스트 컴포넌트 사용 이전

import PokemonList from "../components/PokemonList";
import MOCK_DATA from "../mock";
import Dashboard from "../components/Dashboard";
import { POKEMON, PokeState } from "../context/Pokemon";

const Dex = () => {
  const pokeData = MOCK_DATA;
  const [poke, setPoke] = useState([]);
  //삭제 함수와 추가 함수
  return (
    <div>
      <POKEMON.Provider value={pokeData}>
        <PokeState.Provider value={ {poke, 삭제함수, 추가 함수} }>
          <Dashboard />

          <PokemonList />
        </PokeState.Provider>
      </POKEMON.Provider>
    </div>
  );
};

export default Dex;

 

커스텀 컨텍스트 컴포넌트 사용 이후

import PokemonList from "../components/PokemonList";
import Dashboard from "../components/Dashboard";
import { PokemonProvider } from "../context/Pokemon.jsx";

const Dex = () => {
  return (
    <div>
      <PokemonProvider>
        <Dashboard />

        <PokemonList />
      </PokemonProvider>
    </div>
  );
};

export default Dex;

 

PokemonProvider라는 context 폴더의 커스텀 컴포넌트를 이용하여 작성한 코드이다. context API를 컴포넌트로 만들어서 값을 전달해줄 수 있도록 했다. 이러면 좋은 게 PokemonProvider가 컴포넌트이다보니 재사용이 가능하다는 것이다. 

 

아래는 PokemonProvider 컴포넌트를 이용하여 디테일페이지를 리팩토링한 것이다.

커스텀 컨텍스트 컴포넌트 사용 이전

import { useLocation, useNavigate } from "react-router-dom";
import styled from "styled-components";
import MOCK_DATA from "../mock";

const PokemonDetail = () => {
  const navigate = useNavigate();
  const location = useLocation();
  const queryString = location.search.slice(4);

  const pokeData = MOCK_DATA;
  const pokemon = pokeData[queryString - 1];

  return (
    <div>
      <Img src={pokemon.img_url} alt={pokemon.korean_name} />
      <div>
        <h1>{pokemon.korean_name}</h1>
        <P>타입 : {pokemon.types.join(", ")}</P>
        <P>{pokemon.description}</P>
      </div>
      <Button
        onClick={() => {
          navigate("/dex");
        }}
      >
        뒤로가기
      </Button>
    </div>
  );
};

 

커스텀 컨텍스트 컴포넌트 사용 이후

 

import { useContext } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import styled from "styled-components";
import { PokemonContext, PokemonProvider } from "../context/Pokemon";

const PokemonDetail = () => {
  return (
    <div>
      <PokemonProvider>
        <DetailCard />
      </PokemonProvider>
    </div>
  );
};

 

 

 


 

일단 이로써 필수과제는 다 끝마쳤다. 이번에 context API를 활용하며 상태값 관리의 중요성과 실제 사용방법 같은 것들을 잘 알아갈 수 있었다. 이제 추가과제가 남았는데, 아래 3가지가 주요 목표이다.

  • redux toolkit을 활용하여 리팩토링
  • react-router-dom을 심화사용하여 페이지가 넘어가도 상태값이 초기화되지 않도록 하기
  • modal로 alert 창 꾸미기

다만 개인과제 제출은 다음 주 화요일이니만큼 이러한 추가과제를 하고도 시간이 남으면 사전캠프 때 최초로 작성한 프로젝트들을 리액트로 리팩토링해보는 것도 좋을 것 같다.