像个高手一样在 React 树中传递数据 😎
正常(非BOSS)方法是什么?
将它们分组为变量:
使用 React Context:
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
嘿👋,欢迎回到我的博客。这次,我们来看看如何像个高手一样在 React 组件树中传递数据😎
正常(非BOSS)方法是什么?
我们先来看最简单的方法。直接将数据作为 props 传递到整个组件树中。假设有这样一个场景:我们有一个名为StatusComponent 的组件,它渲染一段简单的文本来描述应用程序的状态。对于我们的示例应用程序,组件树结构如下:
我们示例应用程序的组件树:
-> 应用
-> -> 首页
-> -> -> 侧边栏
-> -> -> -> 状态组件
当然,我这里只是举个简单的例子。实际应用中,组件可能多达几十个。这意味着,如果采用非最优方案,可能会对代码的可维护性和可读性造成极其不利的影响。
// App is calling the HomePage and passing those data as props
<HomePage
successMsg="App initialized"
loadingMsg="Loading app…"
errorMsg="Error encountered"
serverDownMsg="Server down, Try again later!"
/>
// HomePage is calling SideBar and passing its props along
<SideBar
successMsg={this.props.successMsg}
loadingMsg={this.props.loadingMsg}
errorMsg={this.props.errorMsg}
serverDownMsg={this.props.serverDownMsg}
/>
// SideBar is calling StatusComponent and passing its props along
<StatusComponent
successMsg={this.props.successMsg}
loadingMsg={this.props.loadingMsg}
errorMsg={this.props.errorMsg}
serverDownMsg={this.props.serverDownMsg}
/>
// Finally, StatusComponent is using the data passed all the way from App
switch(state) {
case normal : return <p{this.props.successMsg}/>
case loading : return <p{this.props.loadingMsg}/>
case error : return <p{this.props.errorMsg}/>
case serverDown : return <p{this.props.serverDownMsg}/>
}
这很简单也很直接。👍 但是,如果在整个组件树中都使用这种方法,后果可能非常严重。👎 你会不断地在树中传递数据。你的组件会很快变得过于庞大。代码也会重复。(天哪!😠)
我们该怎么办?如何优化这段代码?让我们先来分析一下上面的代码!🧐 这里有两个因素在起作用:
- 存储数据的变量数量(在本例中为 4 个)
- 数据需要经过的组件数量,这里只有两个。应用程序拥有数据,状态组件正在使用数据。剩下的就是主页和侧边栏了。
我手头有两种策略🔥🔥。每种策略都将针对其中一个因素。
将它们分组为变量:
我们先来解决第一个因素,即包含数据的变量数量。
这是 JavaScript!我们可以简单地将这 4 个变量合并成一个。不过,不要合并任何变量。尽量只合并逻辑上相关的变量。幸运的是,在我们的例子中,这 4 个变量都是相关的。
// App is calling the HomePage and passing those grouped variables as props
<HomePage
messages= {
successMsg:"App initialized",
loadingMsg:"Loading app…",
errorMsg:"Error encountered",
serverDownMsg:"Server down, Try again later!"
}
/>
// HomePage is calling SideBar and passing its props along
<SideBar
messages={this.props.messages}
/>
// SideBar is calling StatusComponent and passing its props along
<StatusComponent
messages={this.props.messages}
/>
// Finally, StatusComponent is dividing the grouped variable passed all the way from App
switch(state) {
case(success) : return <p>{this.props.messages.successMsg}</p>
case(loading) : return <p>{this.props.messages.loadingText}</p>
case(error) : return <p>{this.props.messages.errorText}</p>
case(serverDown) : return <p>{this.props.messages.serverDownText}</p>
}
这样看起来好多了,不是吗?今天可以结束了吗?
不!不过,这里还是有可以优化的地方!你看出来了?首页和侧边栏其实并不需要这些数据。它们只是充当数据传递的桥梁。我闻到了代码重复的味道🧐😠。但是我们不能直接删除它。或者,我们可以吗?😈
使用 React Context:
我们来探讨第二个因素,即数据需要经过决策树的层数。这里我们需要一些背景信息。
根据 React 文档,Context提供了一种在组件树中传递数据的方法,无需在每一层手动传递 props。这非常适合传递全局数据,例如语言环境偏好和 UI 主题,因为这些数据会被应用程序中的多个组件使用。
想看个例子吗?当然!
// First we create a context
const MessageContext = React.createContext({
successMsg:"App initialized",
loadingMsg:"Loading app…",
errorMsg:"Error encountered",
serverDownMsg:"Server down, Try again later!"
});
// App render method
<MessageContext.Provider>
<HomePage />
</MessageContext.Provider>
// HomePage is calling SideBar without passing props
<SideBar/>
// SideBar is calling StatusComponent without passing props
<StatusComponent/>
// StatusComponent receiving its required data from the context instead of its parent
static contextType = MessageContext;
render() {
switch(state) {
case(success) : return <p>{this.context.successMsg}</p>
case(loading) : return <p>{this.context.loadingText}</p>
case(error) : return <p>{this.context.errorText}</p>
case(serverDown) : return <p>{this.context.serverDownText}</p>
}
}
如上面的代码所示,我们没有将数据作为 props 传递。通过使用 context,我们无需关心组件树的层级有多深。context 中的数据可以从组件树中的任何位置访问。
您可以在React context 文档页面中找到更多详细信息。
您觉得这篇文章有用吗?
您是否已经了解这些内容?
请在下方评论区留言告诉我。
与往常一样,
快乐编码 🔥🔥
“ك٣ ك٣٣٠”