
[25.02.06 목요일]
개인과제 4일차.
어제까지 Context API 리팩토링을 마무리하고, Redux-ToolKit을 활용한 리팩토링을 시작했다.
Context API를 사용하면서 어느정도 코드는 정리를 해둔 상태여서 바~로 진행하면 되는 사항이었는데, createSlice 파일을 만들고 침묵...
다시 rtk를 활용하라고 하면 할수는 있겠지만, 진행 과정을 기록해 둬야 나중에라도 다시 찾아보고 활용하지 않겠나?
전역 상태관리 라이브러리인 Redux를 더 편하게 사용할 수 있게 만든 툴키트다.
내가 프로젝트를 진행하며 작업했던 과정을 기록해 둔다.
yarn + vite를 기반으로 작업을 진행했다.
yarn add react-redux @reduxjs/toolkit
src/redux/ 폴더 안에 configureStore.js 파일과 <작업명>Slice.js 파일을 생성해준다.
import { createSlice } from "@reduxjs/toolkit";
import MOCK_DATA from "../data/MOCK_DATA";
// 초기값 설정
const initialState = {
pokemonData: MOCK_DATA,
selectedPokemon: localStorage.getItem("myPokemon")
? JSON.parse(localStorage.getItem("myPokemon"))
: [],
};
// ⭐️슬라이스 만들기 & createSlice import 확인
const pokemonSlice = createSlice({
name: "pokemon", // 이 슬라이스의 이름
initialState, // 초기값
reducers: { // 리듀서들
// ✅ 포켓몬 대쉬보드에 추가
addMyPokemon: (state, action) => {
const addPokemon = [
...state.selectedPokemon,
{ ...action.payload, isSelected: true },
];
// 이미 대시보드에 등록한 포켓몬인지 확인
if (state.selectedPokemon.find((item) => item.id === action.payload.id)) {
alert(`${action.payload.korean_name} 이미 보유한 포켓몬입니다.`)
return;
}
// 6마리 초과시 알림
if (state.selectedPokemon.length >= 6) {
alert(`최대 6마리 까지만 등록 가능합니다.`)
return;
}
state.selectedPokemon = addPokemon;
localStorage.setItem("myPokemon", JSON.stringify(addPokemon));
alert(`${action.payload.korean_name} 컬렉션에 추가되었습니다.`)
// ✅ 포켓몬 대쉬보드에서 삭제
removeMyPokemon: (state, action) => {
const removePokemon = state.selectedPokemon.filter(
(item) => item.id !== action.payload.id
);
state.selectedPokemon = removePokemon;
localStorage.setItem("myPokemon", JSON.stringify(removePokemon));
alert(`${action.payload.korean_name} 컬렉션에서 제외되었습니다.`)
},
},
});
// ⭐️현재 작업중인 파일명의 reducer를 내보내준다.
export default pokemonSlice.reducer;
// ⭐️현재 작업 파일의 action들을 내보내준다.
export const { addMyPokemon, removeMyPokemon } = pokemonSlice.actions;
import { configureStore } from "@reduxjs/toolkit";
import pokemonSlice from "./pokemonSlice";
// ⭐️configureStore 생성, import 확인
const store = configureStore({
reducer: {
pokemon: pokemonSlice, // pokemonSlice.js에서 생성한 리듀서객체 이름과 경로 지정, import 확인
},
});
// 다른곳에서 사용할 수 있도록 내보내 주기
export default store;
나의 작업 환경에서는 App.jsx가 최상위 컴포넌트상태.
App.jsximport { Provider } from "react-redux";
import store from "./redux/store";
import Router from "./shared/Router";
function App() {
return (
<>
{/* 생성한 store 연결, Provider와 store import 확인! */}
<Provider store={store}>
<Router />
</Provider>
</>
);
}
export default App;
import React from "react";
import { useSelector } from "react-redux";
import styled from "styled-components";
import PokemonCard from "./PokemonCard";
const PokemonList = () => {
// ⭐️useSelector, import 확인
const pokemonData = useSelector((state) => state.pokemon.pokemonData);
return (
<PokemonListWrapper>
{pokemonData.map((data) => (
<PokemonCard key={data.id} data={data} />
))}
</PokemonListWrapper>
);
};
export default PokemonList;
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useSearchParams } from "react-router-dom";
import styled from "styled-components";
import { removeMyPokemon, addMyPokemon } from "../redux/pokemonSlice";
const Detail = () => {
const pokemonData = useSelector((state) => state.pokemon.pokemonData);
const selectedPokemon = useSelector((state) => state.pokemon.selectedPokemon);
// ⭐️ dispatch를 거쳐 action을 store로 전달, import확인
const dispatch = useDispatch();
const navigate = useNavigate();
const [params, setParams] = useSearchParams();
const pokemonId = params.get("id");
const selectPokemon = pokemonData.find((data) => {
return data.id === +pokemonId;
});
// ⭐️ addMyPokemon, removeMyPokemon함수도 slice생성하고
// actions로 export했기 때문에 사용을 하려면 import 해줘야 한다!!
const handleAddPokemon = (selectPokemon) => {
dispatch(addMyPokemon(selectPokemon));
};
const handleRemovePokemon = (selectPokemon) => {
dispatch(removeMyPokemon(selectPokemon));
};
// 생략
이 과정중에서 Read는 잘 되었는데 C,U,D가 제대로 작동을 하지 않아서 로직에 문제가 있는 줄알았다. 몇번 확인하니 잘못작성한 부분도 있긴 했으나 금방 확인하고 수정하였다.
그런데도 이상하게 함수가 실행되지가 않는것이다. 콘솔에러는 해당 함수가 정의되지 않았다고 하면서 dispatch부터 읽지를 못하는 것이다.
그래서 오타와 useDispatch가 import되었는지 확인했으나, 오타도 없고 import도 잘 되어 있는 상태였다.
찾다 찾다 못찾겠어서 튜터님께 가니, 오류 확인 하시고는 함수도 import했는지 체크해 보라는 것.
아... 하도 import한게 많다 보니 해당함수들도 import한줄 알았다..!
import { removeMyPokemon, addMyPokemon } from "../redux/pokemonSlice";
import하니 바로 해결...🫠
props 지옥에서 해방되었다~ 했더니, import지옥이...?
확실히 전역상태관리라는 것이 편하긴 했다만... 종종 마주칠것만 같은 import 이슈.