使用useReducer时如何避免耦合?

IT技术 reactjs react-hooks
2021-05-10 03:56:01

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

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

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

那么,我忽略了什么以及有什么策略可以解决这个问题?对于它的value,我回到使用回调,在这种情况下,更清晰的代码比重新渲染的性能问题更有意义。

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())