오늘은 이전에 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 창 꾸미기
다만 개인과제 제출은 다음 주 화요일이니만큼 이러한 추가과제를 하고도 시간이 남으면 사전캠프 때 최초로 작성한 프로젝트들을 리액트로 리팩토링해보는 것도 좋을 것 같다.
'til' 카테고리의 다른 글
reducer 만들기 (0) | 2024.08.26 |
---|---|
리액트 숙련 5일 차(完) @개인 과제 200% redux-toolkit, memoization, toaster (0) | 2024.08.23 |
리액트 hook 만들기 (0) | 2024.08.21 |
cra, vite 없이 리액트 프로젝트 생성하기 (0) | 2024.08.20 |
리액트 숙련 3일 차 @개인과제 60% (0) | 2024.08.20 |