使用useReducer如何避免耦合?
How to avoid coupling when using useReducer?
为了防止将回调传递给 child 组件,我正在使用 useReducer
。这避免了 child 组件 re-rendering 在每个 parent 渲染上的问题,但缺点似乎是 parent 和 child 之间的紧密耦合。通过紧密耦合,我的意思是 child 需要明确知道由 parent.
定义的减速器预期的动作形状
例如,想象一下日期选择器组件。在某些时候,此组件需要将新的 date/time 值传递给调用组件,以便可以保存(或以某种方式使用)数据。通过回调,我们可以有一个像 saveDate={onSaveDate}
这样的简单道具。日期选择器通过说 "I expect these props" 来定义合同。具体来说,我希望签名为 newDate => {}
的 saveDate
道具。这个流程对我来说很有意义。
使用 useReducer
,parent 将 dispatch
传递给日期选择器,并且日期选择器需要知道如何创建与 reducer 期望相匹配的操作。这可以通过在某处的模块中定义动作创建者并将它们导入日期选择器来解决,但这对我来说是倒退的。如果日期选择器将从应用程序中的各种组件调用,则所有组件都需要就此接口达成一致 - 操作的形状。这似乎不仅将一个组件与日期选择器耦合在一起,而且将所有使用日期选择器的组件耦合在一起。
那么,我忽略了什么,有什么策略可以解决这个问题?对于它的价值,我回到使用回调,其中更清晰的代码比 re-rendering.
的性能问题更有意义
我建议在父组件中使用 action 类型来柯里化分派,如下所示:
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} />
}
通过这种方式,您的组件与其他组件保持隔离,您可以像使用 hook 之前一样使用它。虽然,如果你经常使用 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())
为了防止将回调传递给 child 组件,我正在使用 useReducer
。这避免了 child 组件 re-rendering 在每个 parent 渲染上的问题,但缺点似乎是 parent 和 child 之间的紧密耦合。通过紧密耦合,我的意思是 child 需要明确知道由 parent.
例如,想象一下日期选择器组件。在某些时候,此组件需要将新的 date/time 值传递给调用组件,以便可以保存(或以某种方式使用)数据。通过回调,我们可以有一个像 saveDate={onSaveDate}
这样的简单道具。日期选择器通过说 "I expect these props" 来定义合同。具体来说,我希望签名为 newDate => {}
的 saveDate
道具。这个流程对我来说很有意义。
使用 useReducer
,parent 将 dispatch
传递给日期选择器,并且日期选择器需要知道如何创建与 reducer 期望相匹配的操作。这可以通过在某处的模块中定义动作创建者并将它们导入日期选择器来解决,但这对我来说是倒退的。如果日期选择器将从应用程序中的各种组件调用,则所有组件都需要就此接口达成一致 - 操作的形状。这似乎不仅将一个组件与日期选择器耦合在一起,而且将所有使用日期选择器的组件耦合在一起。
那么,我忽略了什么,有什么策略可以解决这个问题?对于它的价值,我回到使用回调,其中更清晰的代码比 re-rendering.
的性能问题更有意义我建议在父组件中使用 action 类型来柯里化分派,如下所示:
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} />
}
通过这种方式,您的组件与其他组件保持隔离,您可以像使用 hook 之前一样使用它。虽然,如果你经常使用 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())