使用useReducer时如何避免耦合?

时间:2019-04-03 14:50:16

标签: reactjs react-hooks

为防止将回调传递给子组件,我改用useReducer。这样可以避免在每个父级渲染器上重新渲染子级组件的问题,但缺点是父级和子级之间紧密耦合。通过紧密耦合,我的意思是孩子需要明确地意识到由父母定义的减速器所期望的动作形状。

想象一下,例如一个日期选择器组件。在某个时候,此组件需要将新的日期/时间值传递给调用组件,以便可以保存(或以某种方式使用)数据。使用回调,我们可以有一个简单的道具,例如saveDate={onSaveDate}。日期选择器通过说“我希望这些道具”来定义合同。具体来说,我期望一个saveDate签名的newDate => {}道具。这对我来说很有意义。

使用useReducer,父级将dispatch传递给日期选择器,并且日期选择器需要知道如何创建与减速器期望的动作匹配的动作。可以通过在某个模块中的某个位置定义动作创建者并将其导入日期选择器中来解决此问题,但这对我来说是倒退的。如果从应用程序的各个组件中调用日期选择器,则所有组件都需要在该接口(动作的形状)上达成一致。这似乎不仅将一个组件与日期选择器耦合在一起,而且还将所有使用日期选择器的组件彼此耦合。

那么,我忽略了什么?有什么策略可以解决?出于其价值,我回过头来使用回调,在这些回调中,更干净的代码比重新渲染的性能问题更有意义。

1 个答案:

答案 0 :(得分:1)

我建议在父组件中使用操作类型进行分派分发,如下所示:

const Parent = () => {
  const [state, dispatch] = useReducer(datepickerReducer, initialState)

  // might wanna useCallback here if your DatePicker is pure
  const changeDate = newDate => dispatch({ type: 'CHANGE_DATE', newDate })

  return <DatePicker onChange={changedate} value={state} />
}

这样,您的组件就与其余组件保持隔离,可以像在执行钩子操作之前一样使用它。虽然,如果您经常使用datepickerReducer,那么每次都重新定义changeDate会很烦人,因此我将使用自定义钩子来做到这一点:

const useDatepicker = init => {
  const [date, dispatch] = useReducer(datepickerReducer)
  const changeDate = useCallback(newDate => dispatch({ type: 'CHANGE_DATE', newDate }), [])

  // I prefer using an object, makes it more convenient to reach values that would have been at the end of the array
  return { date, changeDate, /* You could have resetDate here aswell */ }
}

// USAGE
const { date, changeDate } = useDatepicker(new Date())