【发布时间】:2016-12-17 22:33:31
【问题描述】:
我对 React 还很陌生,我正在尝试了解一种让子组件相互通信的干净方式。
在一个简单的组件中,我知道我可以利用 props 将数据传递给子组件,并使用回调让子组件将数据传递回父组件。
在稍微复杂一点的情况下,当我在一个父组件中有多个子组件时,子组件之间的通信会变得有点混乱。我不确定我应该如何为同一级别的子组件相互通信。
就我而言,我决定,也许我可以使用states。所以我会在父组件中有一个state 值,并将它传递给孩子的道具。类似地,父组件中的回调处理程序(从子组件调用)将有助于相应地设置状态,以便状态值通过 React 的绑定从一个子组件传递到另一个子组件。
伪代码可能类似于:
//Inside Parent Component
constructor() {
//initialise state for the child components
this.setState({testList: []});
}
render() {
return (
<div>
<ChildA onSomething={this.onSomethingHandler} testList={this.state.testList} />
<ChildB onSomethingElse={this.onSomethingElseHandler} testList={this.state.testList} />
</div>
);
}
onSomethingHandler(evt):void {
if(blah.blah.blah) this.setState({testList: this.state.testList.splice().push(evt.value)};
}
onSomethingElseHandler(evt):void {
//Some other complex biz logic...
if(blah.blah.blah) this.setState({testList: this.state.testList.splice().push(somethingOtherStuffDueToLogic)};
}
//Inside ChildA Component
export IChildAProps {
onSomething: (evt)=>void
}
render() {
//Do some logic from the value in testList property
if(this.state.testList == blah blah)...
return (
<button onClick={this.props.onSomething({id:321, value:"wassup! I'm ChildA."})}>ChildA</button>
)
}
//Inside ChildB Component
export IChildBProps {
onSomethingElse: (evt)=>void
}
render() {
//Do some logic from the value in testList property
if(this.state.testList == blah blah)...
return (
<button onClick={this.props.onSomething({id:123, value:"yo! I'm ChildB."})}>ChildB</button>
)
}
此时,我开始怀疑这两个处理方法中的逻辑,即父组件中的onSomethingHandler() 和onSomethingElseHandler(),是否真的应该驻留在子组件本身中?我之所以想到这一点,是因为这些逻辑看起来像是子组件应该自己处理以达到其目的的东西。父组件不应该为他们这样做,否则它可能会变得混乱。但我别无选择,因为我如何处理他们的沟通。除此之外,我还创建了一个新状态,只是为了让他们交流。
到目前为止,这仍然是相对可控的。但是在我自己的实验中,它已经到了一个阶段,我将子组件嵌套在另一个子组件中,这些子组件需要在相同(或有时不同)级别的其他子组件之间进行通信。使用状态进行通信也意味着我到处都有许多个状态,这对我来说不是一个好主意。父组件最终使用了大量杂乱无章的回调处理程序方法来管理所有数据在组件树上上下的传播。
您可以在上图中看到,ChildB 最终拥有另一个状态,只是为了帮助在其子组件之间传递该信息。
我确定我错过了一些我应该了解的关于 React 的知识。我在父组件中的回调似乎有点太多,只是为了处理数据传播。我应该如何真正以干净和可维护的方式组织子组件的通信?
【问题讨论】:
-
如果我理解正确,那么您将共享资源(
testList)从父级传递给所有子级。我建议不要这样做,因为它很难管理和控制/同步,如果由于某种原因这个testList的实例在父级中发生变化会发生什么?简单地保持您在简单案例中描述的方式有什么问题?当 childA 发生某些事情时,它使用回调通知父级,然后父级决定 childB 是否需要知道它,如果需要,则通过将新道具传递给 childB 来传递该信息。 -
但是如果
ChildB_1里面的ChildB也需要那条信息呢?我是否会进一步传播该信息?在这种情况下,testList看起来像是一个共享资源。但我认为我还有其他状态,例如this.state.panelOpen='true/false'、this.state.currentMode=0/1/2等。不知何故,我不断遇到需要将这些信息传递给不同级别的多个子组件的情况,这让我发疯了带着所有凌乱的回调。 -
这很容易,除非我错过了什么。当您将信息从父级传递给 childB 时,您在
Parent.render方法中执行此操作,然后它会看到 childB 的道具是“脏的”,因此它使用新道具调用 childB 的渲染。当childB.render方法被调用时,它将使用新的道具调用childB_1.render方法,该道具将具有此新信息。这似乎是一个很长的路要走,可以通过共享资源更轻松地完成某些事情,但是如果您考虑一下,这实际上可以简化事情,因为您不必担心其他组件的状态 -
@NitzanTomer 是的,这是有道理的!事实上,我最近也发现了这一点,React 会检查脏道具以重新渲染。唯一的缺点是我必须将道具绑定到一个状态。所以我最终还是为此目的为状态创建了一个数字,但是我通过这个大大减少了子组件中的回调和不必要的状态。但是,我仍然必须通过树将道具从一个组件向下传递到另一个组件,以传递信息。通常,中间组件甚至不需要 props,它们只是将其传递给其他需要它的子组件。
-
为什么需要绑定 props 到 state?一个 react 组件应该有一个 render 方法,它使用它的 state 和 props 来决定它应该如何渲染。组件可以更改自己的状态(使用
setState),这将导致组件再次被渲染。当父母希望再次渲染孩子时,它会更改该孩子的道具。您的父母可以使用其状态为孩子创建所需的道具,但状态不应绑定到道具。
标签: javascript reactjs typescript architecture