sprint-cmarket-redux (useSelector(),useDispatch())

flobeeee·2021년 2월 22일
0

Sprint

목록 보기
16/25
post-thumbnail

🌵 과제를 시작하기 전에

오전에 Redux 에 대해 공부를 하고, 바로 과제에 투입됐다.
공부하면서 느낀 건, 예제는 소중하다는 것이다.

일단 과제를 fork -> clone 했다.
나는 주로 package.json 을 제일 먼저 확인한다.
dependencies에 어떤 항목이 있는지 보는 것도 도움이 된다.
오전에 공부할 때, toolkit 도 공부해야하나 고민했는데, 다 있었다. 우선은 기본 Redux로 구현하려한다.

"dependencies" : {
    "@reduxjs/toolkit": "^1.1.0",
    "redux": "^4.0.5",
    "redux-thunk": "^2.3.0",
    .
    .
    .
}

npm run install 을 했다.

파일들을 보면서 hooks로 cmarket 구현하길 잘했다는 생각이 들었다. beta 버전이라서 안해도 됐었지만 나는 hooks 를 이용해보려고 진행했었다.
그때보다 더 늘어난 파일을 보니.. 어디서부터 해야할지 막막했다.
이 엄청난 파일들을 보라. .ㅎ

🌵 과제 진행 순서

  • npm run test 를 통해 순서대로 진행했다.
  1. index.js 에서 action 함수를 먼저 작성해줬다.

특정파라미터를 받아서 해당 파라미터를 적용한 객체를 반환하는 함수이다. 이 객체는 우편 송장 역할을 한다.

return {
    type: CHANGE_NUMBER, // type는 꼭 있어야한다.
    payload: {
      // 여기에 변경할 키와 값을 넣어주면 된다.
    }
  }
  1. itemResucer.js 에서 reducer 를 작성했다.

reducer는 state와 action을 input 값으로 받아서 새로운 state 를 리턴한다.

const itemReducer = (state = initialState, action) => {

  switch (action.type) {
    case ADD_TO_CART:
      //TODO
      return Object.assign({}, state, {
        cartItems: [...state.cartItems, action.payload]
      }) //데이터를 보면 객체속 객체라서 이렇게 복사하는 것 같다(유어클래스 예시를 그대로 가져왔다.)

    case REMOVE_FROM_CART:
      //TODO
    
    case SET_QUANTITY:
      let idx = state.cartItems.findIndex(el => el.itemId === action.payload.itemId)
      //TODO
      
    default:
      return state;
  }
}

SET_QUANTITY 부분에서 조건문을 작성할때, key가 비슷해서 헷갈렸다.
action.payload.itemId 와 map 돌릴때 item.itemId
(initialState를 확인했을 때, items.id 도 있다. :전체아이템)

  1. pages 폴더안 파일들에 dispatch 를 추가했다.

dispatch는 action을 파라미터로 받는다.
1에서 작성한 action함수실행을 파라미터로 넣어줬다.

그렇게해서 이번에도 완성된 Cmarket!

🌵 파일 구성 분석

처음 파일의 양을 봤을 때는 오들오들 떨었지만,
막상 다 완성하니 작성한 코드는 몇줄 안 된다.
과제는 통과했지만 개념적으로 부족한 느낌이다.

그래서 구성을 분석해봤다.
1. actions 폴더 index.js 에 action 함수들이 전부 있다.
2. components 폴더의 파일들에 useSelector() 가 있는 것을 발견했다.

import { useSelector } from 'react-redux'; // redux 발견

function Nav() {

  const state = useSelector(state => state.itemReducer);
  // useSelector() 발견!
  return (
    // 상략
    <Link to="/shoppingcart">
      장바구니<span id="nav-item-counter">{state.cartItems.length}</span>
    </Link>
    //하략
    )
}

useSelector()

useSelector()는 컴포넌트와 state를 연결해준다. 컴포넌트에서 useSelector 메소드를 통해 store의 state에 접근할 수 있다. useSelector의 전달인자로는 콜백 함수를 받으며 콜백 함수의 전달인자로는 state 값이 들어간다.

Nav는 우측상단에 장바구니에 몇개의 아이템을 받았는지 알려준다. 이때 state를 받을 필요성이 있어서, 저렇게 코드가 쓰여져 있는 것 같다.

  1. pages 폴더의 파일들에 useDispatch() 발견!
import { useSelector, useDispatch } from 'react-redux';

function ItemListContainer() {
  const state = useSelector(state => state.itemReducer);
  const { items, cartItems } = state;
  const dispatch = useDispatch(); // 발견!

  const handleClick = (item) => {
    if (!cartItems.map((el) => el.itemId).includes(item.id)) {
      //TODO: dispatch 함수를 호출하여 아이템 추가에 대한 액션을 전달하세요.
      dispatch(notify(`장바구니에 ${item.name}이(가) 추가되었습니다.`))
    }
    else {
      dispatch(notify('이미 추가된 상품입니다.'))
    }
  }

  return (
    <div id="item-list-container">
      <div id="item-list-body">
        <div id="item-list-title">쓸모없는 선물 모음</div>
        {items.map((item, idx) => <Item item={item} key={idx} handleClick={() => {
          handleClick(item)
        }} />)}
      </div>
    </div>
  );
}

export default ItemListContainer;

useDispatch()

handleClick 으로 item에 대한 정보를 받아오면 dispatch 로 action을 reducer에게 전달해주는코드이다. (dispatch는 이제 내가 작성해야한다.)

그런데 공식문서 예제를 보면 store.dispatch({type: 'INCREMENT'}); 처럼 단순하게 dispatch를 사용한다. 위 과제코드를 보면 const dispatch = useDispatch(); 이렇게 할당해와서 쓴다. 무슨 차이일까? useDispatch()는 컴포넌트에서 dispatch를 쓰기위해 사용하는 것일까? (알아봐야겠다.)

[공식문서 redux-hook]

공식문서예제를 보면 그렇게 쓰라고 명시되어있다. 이대로 쓰면 될 듯하다.

import React from 'react'
import { useDispatch } from 'react-redux'

export const CounterComponent = ({ value }) => {
  const dispatch = useDispatch()

  return (
    <div>
      <span>{value}</span>
      <button onClick={() => dispatch({ type: 'increment-counter' })}>
        Increment counter
      </button>
    </div>
  )
}

🌵 후기

리액트만 사용했을 때는 props를 아래로 내려주려고 많은 파일과 코드를 수정했다. 내리다가 props 이름의 철자를 빼먹는 등으로 에러를 자주 만났다.

리덕스를 사용하면서, 어떤 컴포넌트에 dispatch를 쓸건지 어떤 컴포넌트에서 useSelector()을 사용할건지 명확히 알고있다면, 그 부분만 수정할 수 있어서 효율적이었다.

어려웠던 점은 파일이 많다보니, 코드를 내보내고 받아오는 것은 나중에는 직접해야할텐데 매우 복잡할 것 같아서 걱정이 된다. 그래도 우선 눈 앞에 있는 것부터 먼저 잘 숙지해야겠다.

profile
기록하는 백엔드 개발자

0개의 댓글