ajax로 불러온 json데이터 redux toolit 사용하여 store.js에 저장하기

신혜원·2023년 9월 3일
0
post-thumbnail
  • 매번 컴포넌트에서 useEffect로 ajax를 이용해 json 파일을 불러 올 수 없어 Redux-toolkit을 사용했다.

(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에 대해 조금 더 깊이있게 공부해보았다.


What is Redux ?

리덕스는 상태 관리 라이브러리 중 하나로 현재까지 가장 많이 쓰이고 있다.

  • 상태관리란?
    UI와 UX에 맞게 데이터를 관리하거나, 서버를 주고받는 데이터를 관리하는 것을 말한다.

내가 불편함을 겪었던 것 (한 컴포넌트의 함수를 props형태로 다른 컴포넌트로 전달하고 또 그것을 props 형태로 또 다른 컴포넌트로 전달하고...) 이런 복잡한 구조는 props 전달로 유지보수 또는 props 추적을 힘들게 하는 Props drilling을 야기한다고 한다.

따라서 상태관리 라이브러리는 이러한 문제들을 해결하기 위해 고안되었다.

Redux 기본 용어

리덕스의 기본 용어부터 제대로!! 알아보자.

Store

스토어는 컴포넌트의 상태를 관리하는 저장소이다.
하나의 프로젝트는 하나의 스토어만 가질 수 있다.

Action

스토어의 상태를 변경하기 위해서는 액션을 생성해야한다.
액션은 객체이며, 반드시 type을 가져야한다.
액션 객체는 액션생성함수에 의해서 만들어진다.

Reducer

리듀서는 현재 상태와 액션 객체를 받아 새로운 상태를 리턴하는 함수이다.

Dispatch

디스패치는 스토어 내장함수 중 하나이며, 액션객체를 넘겨줘 상태를 업데이트 시켜주는 역할을 한다.

Subscribe

스토어의 내장함수 중 하나로 리듀서가 호출될 때 서브스크라이브된 함수 및 객체를 호출한다.


  1. UI가 처음 렌더링 될 때, UI 컴포넌트는 리덕스 스토어의 상태에 접근하여 해당 상태를 렌더링한다.
  2. 이후 UI에서 상태가 변경되면 앱은 디스패치를 실행해 액션을 일으킨다.
  3. 새로운 액션을 받은 스토어는 리듀서를 실행하고 리듀서를 통해 나온 값을 새로운 상태로 저장한다.
  4. 서브스크라이브된 UI는 상태 업데이트로 변경된 데이터를 새롭게 렌더링한다.
  • 그렇다면 Redux 와 Redux-toolkit의 차이는?
    간단히 얘기하자면 Redux 를 사용할때는 Redux 외에도 Redux-actions 라던가 redux-thunk라던가 뭔가 많다.
    그래서 나온게 redux-toolkit이고 이걸 쓰면 지저분하게 이것저것 설치할 필요가 없다는 말씀!🤷🏻‍♀️

이렇게 공부하고 나서 다시 코드를 보니 내 코드에는 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데이터를 받아온것이 배열형태가 아닌지도 확인했다. (모두 이상 무ㅠㅠ...)

  • 그렇다면 다른 부분에서 item상태에 영향을 주는 것이 아닐까 싶어 찾아보았는데 itme을 적은 부분은 아래부분 말고는 없었다.
<ProductList
        shopItems={
          selectedCategory === null
            ? shopItems
            : shopItems.filter((item) => item.type === selectedCategory)
        }
      />
  • 하지만 이는 item에 어떤 의미도 없는 임시 변수이기 때문에 영향을 준다고 생각하지 않았다.

  • state변경이 잘 되더라도 혹시 Detail.js 에서 데이터를 가져오면서 문제가 생기는 것이 아닐까? 라는 생각에 useSelector의 동작을 확인했다.

console.log(typeof a, a.length);

-> object 0 출력

  • 이로써 상태 a는 빈 객체임을 알 수 있었고 이제 왜 Detail 컴포넌트가 렌더링 될 때 state.item이 빈 객체로 유지되는지 이유를 찾아야했다.
changeItem: (state, action) => {
  console.log(action.payload);
  return action.payload;
},

-> 빈 칸 출력

  • 이것은 changeItem 액션이 디스패치 되지 않았다는 것을 의미한다...

  • 이런식으로 계속 비슷하지만 조금은 다르게 계속 수정을 해가며 코드를 확인하여 원인을 조금 좁혀보았다.

  1. 렌더링 순서 문제
  2. item의 데이터가 업데이트 되지 않음
  3. 업데이트가 되더라도 Detail컴포넌트에 반영되지 않음
  • 현재 Shop페이지와 Detail 페이지는 서로 다른 라우트로 분리되어있다.

  • 만약 사용자가 /detail 페이지에 직접 접근하거나 페이지를 refresh한다면 Shop 페이지가 로드되지 않았기 때문에 Detail페이지에서는 Redux스토어에 데이터가 설정되지 않았을 것이다.
    이로인해 Detail 페이지에 데이터를 조회할 때 문제가 발생 할 수 있다.

  • 이를 해결하기 위해 데이터 로딩 위치를 변경해보았다.
    어차피 shop.js에서도 store에 저장되는 item을 쓸 것이기 때문에 App.js 에서 useEffect를 사용해 데이터를 불러왔다.

드디어 떴다..!

0개의 댓글