(shop.js)
(store.js)
(detail.js)
store.js의 initialState에 다른 컴포넌트에서 ajax로 가져온 json데이터를 넣으려고 한다.
그래서 state변경함수 changeItem을 넣고 axios로 가져온 데이터를 dispatch하여 changeItem에 넣었다.
redux 를 사용 할 Detail.js 에서 useSelector을 사용해 데이터 전달이 잘 되었는지 확인하기 위해 console.log(a)를 해보았지만 콘솔창에 item="" 이렇게 state가 없는 상태로 떴다.
Redux 가 아닌 간편한 Redux-toolkit으로 프로젝트를 만들었기에 redux에 대한 지식은 사실 얕은 편이었다.
그래서 우선적으로 Redux에 대해 조금 더 깊이있게 공부해보았다.
리덕스는 상태 관리 라이브러리 중 하나로 현재까지 가장 많이 쓰이고 있다.
내가 불편함을 겪었던 것 (한 컴포넌트의 함수를 props형태로 다른 컴포넌트로 전달하고 또 그것을 props 형태로 또 다른 컴포넌트로 전달하고...) 이런 복잡한 구조는 props 전달로 유지보수 또는 props 추적을 힘들게 하는 Props drilling을 야기한다고 한다.
따라서 상태관리 라이브러리는 이러한 문제들을 해결하기 위해 고안되었다.
리덕스의 기본 용어부터 제대로!! 알아보자.
스토어는 컴포넌트의 상태를 관리하는 저장소이다.
하나의 프로젝트는 하나의 스토어만 가질 수 있다.
스토어의 상태를 변경하기 위해서는 액션을 생성해야한다.
액션은 객체이며, 반드시 type을 가져야한다.
액션 객체는 액션생성함수에 의해서 만들어진다.
리듀서는 현재 상태와 액션 객체를 받아 새로운 상태를 리턴하는 함수이다.
디스패치는 스토어 내장함수 중 하나이며, 액션객체를 넘겨줘 상태를 업데이트 시켜주는 역할을 한다.
스토어의 내장함수 중 하나로 리듀서가 호출될 때 서브스크라이브된 함수 및 객체를 호출한다.
이렇게 공부하고 나서 다시 코드를 보니 내 코드에는 state변경함수에 action 이 없었다.
let item = createSlice({
name: "item",
initialState: [],
reducers: {
changeItem: (state, action) => {
state = action.payload;
},
},
});
그래서 단순히 state = action.payload를 하면 안되나 싶었지만
"createSlice" 에서 정의된 리듀서는 "immer" 이라는 라이브러리를 사용하여 불변성을 관리한다고 한다.
이 라이브러리는 직접 상태를 변경할 수 있는것처럼 코드를 작성하게 해주지만, 실제로는 불변성을 유지하면서 새로운 상태를 생성한다.
이러한 방식으로 동작하기 때문에 state = action.payload;
와 같은 코드는 작동하지 않는다.
따라서 아래와 같이 수정했다.
changeItem: (state, action) => {
return action.payload;
},
console.log창을 보면 {item: Array(0)} 이라고 뜬다.
이 말은 item 슬라이스의 초기상태가 빈 배열로 설정되어있고, 아직 어떠한 데이터도 추가되지 않았음을 의미한다.
쉽게 말해 state변경이 이루어지지 않는다는 말...
초기값을 배열로도 바꾸고 ajax로 json데이터를 받아온것이 배열형태가 아닌지도 확인했다. (모두 이상 무ㅠㅠ...)
<ProductList
shopItems={
selectedCategory === null
? shopItems
: shopItems.filter((item) => item.type === selectedCategory)
}
/>
하지만 이는 item에 어떤 의미도 없는 임시 변수이기 때문에 영향을 준다고 생각하지 않았다.
state변경이 잘 되더라도 혹시 Detail.js 에서 데이터를 가져오면서 문제가 생기는 것이 아닐까? 라는 생각에 useSelector의 동작을 확인했다.
console.log(typeof a, a.length);
-> object 0 출력
changeItem: (state, action) => {
console.log(action.payload);
return action.payload;
},
-> 빈 칸 출력
이것은 changeItem 액션이 디스패치 되지 않았다는 것을 의미한다...
이런식으로 계속 비슷하지만 조금은 다르게 계속 수정을 해가며 코드를 확인하여 원인을 조금 좁혀보았다.
현재 Shop페이지와 Detail 페이지는 서로 다른 라우트로 분리되어있다.
만약 사용자가 /detail 페이지에 직접 접근하거나 페이지를 refresh한다면 Shop 페이지가 로드되지 않았기 때문에 Detail페이지에서는 Redux스토어에 데이터가 설정되지 않았을 것이다.
이로인해 Detail 페이지에 데이터를 조회할 때 문제가 발생 할 수 있다.
이를 해결하기 위해 데이터 로딩 위치를 변경해보았다.
어차피 shop.js에서도 store에 저장되는 item을 쓸 것이기 때문에 App.js 에서 useEffect를 사용해 데이터를 불러왔다.
드디어 떴다..!