您可能不需要React上下文

React 16.3最终使Context API变得稳定。 从那时起,许多开发人员开始使用它来解决“ prop-drilling”问题-这个问题是您需要沿着不使用它的组件沿组件树向下传递一个prop ,以便访问被渲染的组件中的propReact文档指出了Context API的意图,如下所示:

在典型的React应用程序中, 数据是通过props自上而下(父级到子级)传递的,但是对于应用程序中许多组件所需的某些类型的props(例如,语言环境首选项,UI主题)而言,这可能会很麻烦。 上下文提供了一种在组件之间共享类似值的方法,而不必在树的每个级别上显式传递道具。
上下文旨在共享可被视为 React组件树(例如当前经过身份验证的用户,主题或首选语言)的“全局”数据

让我们看一下跟踪用户活动的示例。 为此,我们希望每次用户单击UI元素时都调用某个track函数。

普通React中的Tracker
const track = event => console.log(`${event} occured`);

class App extends React.Component {
render() {
return <Toolbar track={track} />;
}
}

function Toolbar(props) {
return (
<div>
<TrackedButton track={props.track} />
</div>
);
}

function TrackedButton(props) {
const onClick = () => {
props.track("button click");
// do something on click
};
return <Button onClick={onClick} />;
}

我们需要在应用程序的许多不同组件中使用track功能,并且使用没有任何高级模式的React,即使AppToolbar没有使用它,也需要在整个组件树中传递track

上下文跟踪器

我们可以使用新的React Context API将track函数注入所需的组件中:

const track = event => console.log(`${event} occured`);
const TrackerContext = React.createContext(track);

class App extends React.Component {
render() {
return (
<TrackerContext.Provider value={track}>
<Toolbar />
</TrackerContext.Provider>
);
}
}

function Toolbar(props) {
return (
<div>
{/* does not need to forward props anymore */}
<TrackedButton />
</div>
);
}

function TrackedButton(props) {
return (
<TrackerContext.Consumer>
{value => (
<Button
onClick={() => {
// call track
value("button click");
// do something on click
}}
/>
)}
</TrackerContext.Consumer>
);
}

我们创建一个TrackerContext ,用Provider包裹根组件,这使track函数作为TrackedButton组件中的value使用。

但是,这不是我们在Context API之前无法做到的,您始终可以在React中使用HOC (高阶组件) 来做到这一点 。 使用HOC,该代码甚至更具可读性。

跟踪器作为HOC

我们可以创建一个HOC,一个接受组件并返回一个新组件的函数,该组件将对原始组件进行一些增强。 在我们的例子中,我们将track功能作为prop注入到内部组件中。

const track = event => console.log(`${event} occured`);
const withTracker = track => Component => (props) => (
<Component track={track} {...props}/>
);

class App extends React.Component {
render() {
return (
/* no need to wrap root Component */
<Toolbar />
);
}
}

function Toolbar(props) {
return (
<div>
{/* need to use the HOC here */}
<TrackedButtonWrapped />
</div>
);
}

// TrackedButton is the same as in first solution
function TrackedButton(props) {
const onClick = () => {
props.track("button click");
// do something on click
};
return <Button onClick={onClick} />;
}
// Need to create a higher-order component out of TrackedButton
const TrackedButtonWrapped = withTracker(track)(TrackedButton)

这样做的好处是代码比使用Context更干净:

  1. App不再需要ContextProvider包装器。
  2. TrackedButton与纯React解决方案中的组件完全相同。 检索track功能不再是它的责任。 这是因为我们将prop检索转移到了TrackedButtonWrapped HOC中 ,该HOC代替了我们在Toolbar呈现。
那么React.createContext没用吗?

让我们回到React文档中给出的示例。 在那里, Context用于主题应用程序。

上下文主题

该代码类似于“ 上下文跟踪”示例。 ThemeContext.Provider提供theme切换 theme的功能,该功能在根组件中设置state 。 这些变量仅在需要的地方使用-在ThemedButton为按钮设置样式并在单击按钮时切换主题。

const ThemeContext = React.createContext();

class App extends React.Component {
state = {
theme: 'light'
}

toggleTheme = () => {
this.setState(({ theme }) => ({
theme: theme === 'light' ? 'dark' : 'light',
}));
}

render() {
const value = {
theme: this.state.theme,
toggleTheme: this.toggleTheme,
}
return (
<ThemeContext.Provider value={value}>
<Toolbar />
</ThemeContext.Provider>
);
}
}

function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}

function ThemedButton(props) {
return (
<ThemeContext.Consumer>
{({ theme, toggleTheme }) => <Button theme={theme} onClick={toggleTheme}/>}
</ThemeContext.Consumer>
);
}
主题为HOC:首先尝试

让我们尝试应用与Tracking Theming相同的HOC模式。

剧透:这行不通。
const withTheme = InnerComponent => class extends React.Component {
state = {
theme: 'light'
}

toggleTheme = () => {
this.setState(({ theme }) => ({
theme: theme === 'light' ? 'dark' : 'light',
}));
}

render() {
return (
<InnerComponent theme={this.state.theme} toggleTheme={this.toggleTheme} />
)
}
}

class App extends React.Component {
render() {
return (
// again no Provider needed
<Toolbar />
);
}
}

function Toolbar(props) {
return (
<div>
{/* use the HOC here */}
<ThemedButtonWrapped />
{/* let's add another Button here */}
<ThemedButtonWrapped />
</div>
);
}

function ThemedButton(props) {
return <Button onClick={props.toggleTheme} theme={props.theme} />;
}
// Need to create a higher-order component out of ThemedButton
const ThemedButtonWrapped = withTheme(ThemedButton)

怎么了 如果我们添加另一个ThemedButton ,您会注意到它在这里不起作用。 每次创建HOC时,组件实例都以全新state开始,因此按钮的主题彼此独立。 你可以在这里玩。

为什么在跟踪示例中有效? 在跟踪示例中,数据( track功能)是静态的,并且从未更改,因此,使用相同功能的每个Button实例在这里都不是问题。

这是Context API相对于HOC pattern的最大优势,以及它如此强大的原因: 使用 Context ,数据在所有 Consumers 之间共享

反应上下文与HOC

摘要

这又是React文档对Context用例的Context

上下文旨在共享可被视为React组件树的“全局”数据

我还要进一步说Context API用于由多个组件实例使用的全局动态数据的。 对于静态数据,您可能不需要Context 。 总是可以用注入props的更简单的HOC代替它。

这是如何确定是否使用React的Context API的一般指南:

反应上下文流程图

最初发布于cmichel.io

From: https://hackernoon.com/you-might-not-need-react-context-e1adb35b2e04

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值