bindActionCreators 보다는 useDispatch를 사용하자

윤상준·2023년 3월 5일
0

Redux

목록 보기
1/2
post-thumbnail

bindActionCreators

이름에서 알 수 있듯 Action Creators를 하나로 바인딩하는 기능을 제공한다.

서로 다른 리듀서의 Action Creators를 다음과 같이 하나로 바인딩 할 수 있다.

  const dispatch = useDispatch()
  
  const action = useMemo(() => {
    return bindActionCreators(
      {
        ACTION_CREATOR_FROM_A,
        ACTION_CREATOR_FROM_B,
        ACTION_CREATOR_FROM_C,
      },
      dispatch,
    )
  }, [dispatch])

useActions

React-Redux에서는 useActions() 훅으로 이 기능을 제공했다.

import { bindActionCreators } from 'redux'
import { useDispatch } from 'react-redux'
import { useMemo } from 'react'

export function useActions(actions, deps) {
  const dispatch = useDispatch()
  return useMemo(
    () => {
      if (Array.isArray(actions)) {
        return actions.map((a) => bindActionCreators(a, dispatch))
      }
      return bindActionCreators(actions, dispatch)
    },
    deps ? [dispatch, ...deps] : [dispatch]
  )
}

하지만 이 기능은 React-Redux의 v7.1.0-alpha.4 부터 제거되었다.

그 이유는 다음과 같다.

This hook was in our original alpha release, but removed in v7.1.0-alpha.4, based on Dan Abramov's suggestion. That suggestion was based on "binding action creators" not being as useful in a hooks-based use case, and causing too much conceptual overhead and syntactic complexity.
이 훅은 원래 알파 릴리즈 버전에 포함되어있었지만, Dan Abramov의 제안에 따라 v7.1.0-alpha.4 부터 제거되었습니다. 그의 제안은, "액션 생성자들을 하나로 바인딩하는 것은" Hooks 시스템에서 그리 유용하지 않을 뿐만 아니라, 개념적인 과부화와 문법적인 복잡도를 높인다는 것이었습니다.

Dan Abramov의 멘션

저는 모든 "액션 생성자"의 의존성을 useEffect, useCallback 등의 의존성 목록에 넣는 것이 짜증난다는 피드백을 많이 보고 있습니다. 그래서 저는 useActions() 훅이 더 이상 불필요하고, useDispatch() 훅이 Hooks 세계에 더 맞는 방법이라고 강력하게 주장하고 싶습니다. 자세한 설명은 이 댓글에서 확인하세요.

저는 예전에 제가 "액션 생성자를 바인딩"하는 패턴의 사용을 추진했다는걸 알고 있습니다. 저는 저희가 Redux에 추가한 이 "현명한 지름길"에 대해서 다소 후회하고 있습니다. 왜냐하면 사람들이 이러한 한 줄 짜리 "짧은" 변화에 너무 집착해서 큰 그림을 놓치고 있기 때문입니다. 또한 이 방식은 데이터의 흐름을 따라가기가 어렵습니다.

특히 Hooks를 사용할 경우, 이 객체 바인딩 되는 그 즉시 해체되어 사용되기 때문에 실질적인 용도가 없습니다. 이 사이에 어떤 독립적인 컴포넌트 계층이 존재하지 않습니다. 따라서 useActions()는 두 가지 유형의 API에서 모두 최악입니다.

useDispatch()를 사용할 경우, 종속성 목록은 실제 종속성을 반영합니다. 왜냐하면 모든 액션 생성자들은 정적이게 되며 컴포넌트 스코프 외부로 이동하기 때문입니다. 생각해보면, 이게 진짜 그들의 모습입니다. 그들은 외부 요소에 종속적이며 컴포넌트 또는 리덕스 스토어의 최상위 레벨에서도 생성되지 않았습니다. 이들을 왜 하나로 묶는 Hook이 필요한지는 "과거의 습관" 외에는 없습니다. 함수 sum(2, 2)를 사용하려면 그냥 sum(2, 2)를 바로 호출하지, 이걸 boundSum에 바인딩 한 다음 boundSum을 호출하지는 않습니다. 이거랑 똑같습니다.

핵심은 useDispatch()로 바로 dispatch 하면 될 것을 굳이 하나로 묶을 필요가 없다는 것이다.

import React from 'react'
import { useDispatch } from 'react-redux'
import { ACTION_CREATOR_FROM_A } from '@/store/app/app.store'

export const Component = () => {
  const dispatch = useDispatch()

  return (
    <div>
      <button onClick={() => dispatch(ACTION_CREATOR_FROM_A)}>
        Increment counter
      </button>
    </div>
  )
}
profile
하고싶은건 많은데 시간이 없다!

0개의 댓글