使用useReducer时如何避免耦合? [英] How to avoid coupling when using useReducer?

查看:36
本文介绍了使用useReducer时如何避免耦合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

To prevent passing callbacks to child components I am using useReducer instead. This avoids the issue of child components re-rendering on each parent render but the downside seems to be a tight coupling between parent and child. By tight coupling, I mean that the child needs to be explicitly aware of the shape of the action expected by the reducer which is defined by the parent.

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

Imagine, for example, a date picker component. At some point this component needs to pass the new date/time value to the calling component so that the data can be saved (or somehow used). With callbacks, we can have a simple prop like saveDate={onSaveDate}. The date picker defines the contract by saying "I expect these props". Specifically, I expect a saveDate prop with signature of newDate => {}. This flow makes sense to me.

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

With useReducer, the parent passes dispatch to the date picker, and the date picker needs to be aware of how to create an action that matches what the reducer expects. This can be solved by defining action creators in a module somewhere and importing them into the date picker but this feels backwards to me. If the date picker will be called from various components in the application, all the components will need to agree on the this interface - the shape of the action. This seems to couple not only one component with the date picker, but all components that use the date picker with each other.

那么,我忽略了什么,有什么策略可以解决这个问题?就其价值而言,我又回到使用回调,在这种情况下,更简洁的代码比重新渲染的性能问题更有意义.

So, what am I overlooking and what strategy exists to deal with this? For what it's worth, I went back to using callbacks where cleaner code makes more sense than the performance concern of re-rendering.

推荐答案

我建议使用父组件中的 action 类型进行派送,如下所示:

I would suggest currying dispatch with the action type in the parent component, like so:

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 会很烦人,所以我会有一个自定义钩子来做:

This way your component stays isolated from the rest and you can use it as you did before hooks. Although, if you are using the datepickerReducer often, it will be annoying to re-define changeDate every time, so I would have a custom hook do it:

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

这篇关于使用useReducer时如何避免耦合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆