react new context API 的一次实践

发布于 2022-11-23 23:29:26 字数 4861 浏览 6 评论 0

最近接到一个简单的内部项目,逻辑并不复杂,就想着不用 redux 了,用 react 的 new context API 试试看,折腾了两天,把过程和感想跟大家分享下。

基本用法

先让我们来看一下这个接口的基本用法:使用它首先需要使用 react 的 createContext 方法创建一个实例:

import React, { createContext } from "react";
const Context = createContext();

Context 实例提供两个组件:Provider 和 Consumer

const ContextProvider = Context.Provider;
const ContextConsumer = Context.Consumer;

其中 ContextProvider 是数据的发布方,而 ContextConsumer 是数据的订阅方。

<ContextProvider value={{ name: "A", age: 18 }}>
  <ContextConsumer>
    {
      context => (
        <div>
          name:&nbsp;
          <span>{context.name}</span>
          &nbsp;age:&nbsp;
          <span>{context.age}</span>
        </div>
      )
    }
  </ContextConsumer>
</ContextProvider>

ContextProvider 是数据的发布方。它拥有一个名为 value 的属性,用于维护数据内容,通过 value 传递给 ContextProvider 的数据会被发布出去。

而 ContextConsumer 是数据的订阅方,它的 props.children 是一个函数,接收的参数是被发布的数据,我们通过调用这个函数来获取被 ContextProvider 发布的数据,并且返回我们想要渲染的组件。

在这个示例中,我们最后在页面上能够显示出 name: A age: 18

关于调用 createContext 方法时候的传参,理论上第一个传参应该是初始化的数据,但是我使用后发现,如果在 ContextProvider的value 属性中不传入对应的属性的话,无法在 ContextConsumer 中获取到那个初始化的属性。

const Context = createContext({ name: "A" });
<Context.Provider value={{ age: 18 }}>
  <Context.Consumer>
    {
      context => (
        <div>
          name:&nbsp;
          <span>{context.name}</span>
          &nbsp;age:&nbsp;
          <span>{context.age}</span>
        </div>
      )
    }
  </Context.Consumer>
</Context.Provider>

这个例子中,name 的值无法被获取到。我目前还没找到原因,如果知道的朋友请告诉我一下,谢谢!

实践

为了适应项目的需求,我主要是对 ContextProvider 和 ContextConsumer 做了封装。

ContextProvider

由于在我的项目中组件需要订阅并且修改和维护被发布的数据,所以我需要有一个可以维护这些数据的地方。因此我创建了一个名为 MyProvider 的高阶组件,并把它放在组件树的顶层,而各个组件需要订阅的数据就存放在 MyProvider 的 state 中,那么我只需要维护它的 state 就能维护这些全局的数据了。

export class MyProvider extends React.Component {
  constructor() {
  super();
  this.state = {
    name: "A",
    age: 18
  };
  this.updateContext = this.updateContext.bind(this);
  }
  updateContext(newData) {
  this.setState(Object.assign({}, this.state, newData));
  }
  render() {
  const contextData = { data: this.state };
  Object.defineProperty(contextData, "updateContext", {
    value: this.updateContext
  });
  return (
    <Context.Provider value={contextData}>
    {this.props.children}
    </Context.Provider>
  );
  }
}

MyProvider 组件返回的是 ContextProvider 组件,并把 MyProvider 的 state 作为要发布的数据绑定到了 ContextProvider 的 value 属性上。

前面讲过,由于其他组件有要修改被发布数据的需求,所以我给数据添加了一个不可修改的方法 updateContext,这个方法能够接收新的数据并更新 MyProvider 的 state,即更新了被发布的数据。

最后,MyProvider 组件将自己的 children 原封不动的传递给 ContextProvider。

ContextConsumer

考虑到 ContextConsumer 作为订阅方使用比较频繁,为了方便其他组件的使用,我将它封装到高阶组件中,并作为函数的返回值使用,如下:

export const MyConsumer = Component => {
  return props => (
  <Context.Consumer>
    {context => {
    return <Component context={context} {...props} />;
    }}
  </Context.Consumer>
  );
};

MyConsumer 函数返回一个高阶组件。在这个高阶组件中,我把 ContextConsumer 提供的数据加入到 Component 的 props 中,这样我只需要在 export 组件的时候调用MyConsumer,并且在组件中使用 this.props.context.data 就能得到被发布的数据了。如下:

class MyComponent extends React.Component {
  addAge() {
  const { data: { age }, updateContext } = this.props.context;
  const newAge = age + 1;
  updateContext({ age: newAge });
  }
  render() {
  const { name, age } = this.props.context.data;
  return (
    <div>
    name:
    <span>{name}</span>
    age:
    <span>{age}</span>
    <button onClick={() => this.addAge()}>add age</button>
    </div>
  );
  }
}

export default Consumer(MyComponent);

在这个例子中,点击按钮,调用 this.props.context.updateContext 方法就可以通过更新 MyProvider 的 state 来修改被发布数据中的 age 的值。

示例代码:react-new-context-api-demo

小结

我折腾了两天之后才反应过来,这不就是一个类似于 redux 的东西吗?

可能由于我 redux 用的多了,对于 Prvider 和 Consumer 的封装下意识的做成了类似 redux 的用法。再加上使用 MyProvider 的 state 作为唯一数据源,又有 updateContext 这个有点像 dispatch 的方法来更新数据,乍一看之下,还是有点redux的影子的。

当然了,我自己写的完全没有 redux 那么好用,也没有reudx那么严谨。所以,后来我又花了一个上午的时间改用了 redux。但是通过这次的实践,也算是熟悉的new  context api 的用法,对 redux 也加深了了解吧。

最后,如果你只是想要订阅数据,new context api 是个不错的选择;但是如果你想要修改和维护被发布的数据,使用redux会更方便和安全。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

列表为空,暂无数据

关于作者

走走停停

暂无简介

0 文章
0 评论
0 人气
更多

推荐作者

深爱成瘾

文章 0 评论 0

甜点

文章 0 评论 0

Ss Yy

文章 0 评论 0

dgmis009

文章 0 评论 0

花想c

文章 0 评论 0

樱花落人离去

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击“接受”或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。