Payload를 알아보는데...

Strickland·2024년 2월 8일

react/redux

목록 보기
1/1

SPA 쇼핑몰을 만들면서 나를 힘들게 한 Redux toolkit.

그 중에서도 날밤을 새우게 고생시킨 payload를 알아보자.



근데 payload를 알아보려면 action을 알아봐야하고, action을 알아보려면 reducer를 알아봐야한다.

먼저 간단히 개념들을 정리해보자.

reducer

간단 정리 : state를 변경하는 함수. 끝.

  • 덧붙여 생각해보자. 상태를 변경하고 싶으면 자연스레 가지고 어떻게 바꿀지가 필요하지 않을까?

  • 그래서 두 개의 파라미터를 받는다. state랑 action.

즉 reducer는 이전 상태(state)와 action을 받아서 새로운 상태를 반환한다.

action

간단 정리 : 상태 변화를 일으키는 동작. 끝.

  • javascript 객체의 형태.
  • 꼭 type 속성을 가져야한다. action의 종류를 구별하는 용도로 사용된다.

useDispatch Hook

간단 정리 : reducer에게 action을 보내는 스토어 내장 함수. 끝.

이제 만든 action을 reducer로 보내서 사용(상태를 변경)해보자.

  • 예시 :
import { useDispatch } from "react-redux"; // import

const dispatch = useDispatch(); // dispatch 생성

<button
	onClick={() => {
    	dispatch({ type: "PLUS_ONE" });
    }}
>
더하기 1
</button>

reducers: {
    PLUS_ONE(state) {
      state.count += 1;
    }
  }

마우스를 클릭 -> dispatch 실행 -> (type이 "PLUS_ONE"인) action을 파라미터로 reducer에 전달

payload

오늘의 주인공 등장.

간단 정리 : action에서 사용자 정의 데이터를 전달하는 속성. 끝.

이제 payload라는 속성을 더해, action을 발생시킨 동작에 필요한 추가적인 정보를 전달할 수 있다.

  • 예시 :
const addAction = {
  type: 'ADD_TODO',
  payload: {
    id: 1,
    text: 'Buy groceries',
    completed: false
  }
};

너도 하고 나도 하는 투두리스트에 새로운 할 일을 추가하는 action을 발생시켜보자.
이 때 action 객체에 payload라는 속성을 추가하면, 할 일에 ID, 내용, 수행여부 불리언과 같은 사용자 정의 데이터를 리듀서에 보낼 수 있는 것이다.


const deleteAction = {
  type: 'DELETE_ITEM',
  payload: {
    id: 5
  }
};

이어서 특정 아이템을 삭제하는 action을 발생시켜보자.
여기서 payload 속성은 id를 가지고 있다. 이 정보를 스토어에 보내서 id와 일치하는 어떤 것을 삭제할 것이다.


쉽죠?



실사용에서 알아보자

SPA 쇼핑몰에서 사용했다.

👉 cart.tsx로 구현한 장바구니 일부

cart.tsx로 구현한 장바구니

  • 구현 목표 :
  1. 왼쪽 라디오버튼을 클릭해서 상품을 선택.

  2. 왼쪽 하단 '선택상품삭제' 버튼을 통해 체크되어있는 상품만 장바구니에서 삭제.


👉 useDispatch()를 사용하는 cart.tsx 의 일부


function cart() {
  const [checkItems, setCheckItems] = useState<number[]>([]);

  // 체크박스 단일 선택
  const handleSingleCheck = (checked: boolean, id: number) => {
    if (checked) {
      // 단일 선택 시 체크된 아이템을 배열에 추가
      setCheckItems((prev) => [...prev, id]);
    } else {
      // 단일 선택 해제 시 체크된 아이템을 제외한 배열 (필터)
      setCheckItems(checkItems.filter((el) => el !== id));
    }
  };

  const deleteHandler = () => {
      dispatch({
        type: deleteItem, // deleteItem action 호출
        payload: {
            checkItems: checkItems, // 선택한 상품들의 id를 payload로 전달
        },
      });
      // 초기화
      setCheckItems([]);
    };
  
  return (
    <button 
      type="button" 
      onClick={deleteHandler}>
      선택상품삭제
    </button>
  );
}

  1. useState 훅을 사용해 checkItems 이라는 빈 배열을 만든다.

  2. handleSingleCheck 라는 함수를 만든다. 라디오 버튼의 boolean 값을 활용해 checkItems 배열에 해당 상품의 id를 담거나 뺀다.

  3. deleteHandler 라는 함수를 만든다. dispatch 함수를 생성한다.

  4. ✔️ 파라미터로 사용된 action을 살펴보자. type은 후술할 deleteItem 이라는 삭제 action을 적고, payload에는 1~2번에서 만든 checkItems 배열을 담는다.

  5. 선택상품삭제 버튼을 클릭하면 deleteHandler 함수가 실행된다. 이제 선택한 상품의 id를 payload를 통해 store로 전달한 후 deleteItem 을 통해 reducer의 상태를 변경한다!


👉 store.ts 의 reducers의 일부


  reducers: {
    deleteItem(
      state, 
      action: PayloadAction<{ checkItems: number[] }>) {
      action.payload.checkItems.forEach(function (v: number) {
        const idx = state.findIndex(function (o) {
          return o.id === v;
        });
        state.splice(idx, 1);  // 선택한 상품들을 장바구니에서 삭제
    },
  },
    

  1. deleteItem이 실행된다.

  2. state에는 cart 리스트가 있다. 서술하지 않았지만, 상품의 고유 식별자(id)도 포함되어 있다.

  3. action.payload.checkItems => 불러온 checkItems. id로 구성된 숫자 배열이다.

  4. forEach 문을 사용해서 배열을 순회한다. 현재 아이템의 id와 일치하는 상품을 찾아서 인덱스를 가져온다.

  5. 찾은 상품을 splice() 메소드를 사용해 장바구니에서 삭제한다.


👉 조금만 더 가보자

reducers: {
  deleteItem(
    state, 
    action: PayloadAction<{ checkItems: number[] }>) {
        const updatedState = state.filter((item) => 
       		!action.payload.checkItems.includes(item.id));
        return updatedState;
      },
    }, 
    

원본 상태를 수정하지 않고, 더욱 간단한 코드로 구현할 수 있도록 수정했다.


회고

쉽죠?

지금이야 개념을 알고 순서를 정리해뒀으니 쉽지. 코드를 구현하기 위해 진짜 literally 날 밤을 새웠다. 금요일에 학원에서 다 못하고 온게 내내 맘에 걸려서 불금을 반납하고 수정을 했다.

이게 무슨 소린가 하면서 한참을 구글링하고, 가이드 문서를 뒤져보고, stack overflow에도 냅다 생각나는 키워드를 집어던졌다.

결국엔 손이 고생하는 콘솔 로깅이 답이 되더라.

리듀서를 콘솔에 찍고... action을 콘솔에 찍고... payload를 액션에 찍고...
'여기에 상품 id를 어떻게 담지' 하면서 이것저것 계속 만들어 넣고 새로고침을 수 천번은 반복했다.

와!! 된다!!! 된다!!! 하고 창 밖을 보니까 해가 막 뜨려 하고 있더라.


원래도 그랬지만 나는 엉덩이 배기게 뭘 해보는 것이 재밌다.

그래도(1) 사람인지라 막히면 순간 힘들긴 하다.

그래도(2) 여기서 '난 못해 더 못한다~' 에서 멈추지 않고

'아 어떤 방법으로 그럼 해볼까? 뭐가 막힌거지? 다시 뜯어보자.' 가 습관적으로 나오기 시작했다.




참조 :
redux-toolkit
Payload[숙련_6]
찾다 못해 내가 쓴다. 뉴비를 위한 React-Redux 튜토리얼

profile
프론트엔드 개발자가 될 거에요!

0개의 댓글