我想出了一个React问题的解决方案,想看看人们的想法。
问题:我有一个非常大的表单组件,其中包含许多子表单,每个子表单都可以展开和最小化。父表单组件已经在管理大量状态,因为所有子表单都向其报告其输入值。还有一个“ErrorBubble”组件。只要表单经过验证并且出现错误,就会出现ErrorBubble并找到表单中的第一个无效字段并移动到该字段。 ErrorBubble还必须在表单大小发生变化时动态更新其位置,如果您最小化或扩展任何子表单,则会发生这种情况。所以,问题是,如何让每个子表单与需要重新定位的ErrorBox进行通信?
传统解决方案:只需让父表单组件管理所有状态即可。每个子表单都会将其展开状态的任何更改报告给父组件,这会导致重新呈现包括ErrorBubble在内的所有内容。
缺点:父组件已经有很多方法并说明它正在管理,我不想添加更多。强制重新呈现整个父表单组件
Redux解决方案:让每个子表单调度一个redux操作,并将ErrorBubble连接到Redux存储。
缺点:要创建的大量样板文件。必须为此创建一个reducer和一个redux商店。必须设计redux动作。必须将ErrorBubble连接到redux。在每个子窗体调整大小时更新redux存储可能效率不高吗?
我的解决方案:我有一个DeferredTask自定义对象帮助器。我在父窗体组件的构造函数中创建它的一个实例,并将其保存为状态。这是自定义对象:
export class DeferredTask {
constructor () {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve
this.reject = reject
this.reset = function () {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve
this.reject = reject
})
}
})
}
}
然后我将this.state.deferredTask传递给所有子表单,并将ErrorBubble传递给prop。
每当ErrorBubble挂载时,它会运行一个侦听此deferredTask来解析的方法,当它卸载时,它会拒绝任务将其关闭,以便它不会永久保留:
componentDidMount() {
this.repositionErrorBubble()
this.deferredTask()
}
deferredTask = () => {
this.props.deferredTask.reset()
this.props.deferredTask.promise
.then(()=>{
if(this._calledComponentWillUnmount) {
return
}
this.repositionErrorBubble()
this.deferredTask()
})
}
componentWillUnmount () {
this.props.deferredTask.reject()
}
每个子表单都有:
componentDidUpdate () {
this.props.deferredTask.resolve()
}
现在,每次任何子表单更新时,它们都会解析promise并且ErrorBubble会运行then()。它需要检查是否计划卸载ErrorBubble组件,因为您无法更新卸载组件的状态。否则,它运行代码以重新定位ErrorBubble,然后重置promise并开始再次收听它。
优点:只创建一个状态并从父表单组件传递一个支柱。连接这些组件的相当小的代码表面区域。不必通过常规道具渠道进行更新。 componentWillReceiveProps已经臃肿了很多其他检查。
它像一个准酒吧子模式但更整洁?
你们觉得怎么样?这是反模式,因为数据是水平传递而不是垂直传递的?请记住,deferredTask对象仍然可以在父组件中作为状态使用并且正在向下传递...这会使它更好吗?
使用异步承诺是否有陷阱?它能咬我的屁股吗?因为触发解决方案的唯一事情是连续的用户交互,并且在每次交互后重置承诺,所以它不应该引起任何混淆,承诺正在解决它吗?到目前为止,我已经尝试将子窗体大小调整为垃圾邮件并且没有造成任何问题。
有没有更好的方法可以使用React?