资讯专栏INFORMATION COLUMN

react new context API的一次实践(补充)

kaka / 2826人阅读

摘要:作为数据的发布方,它拥有一个名为的属性,用于维护数据内容,通过传递给的数据会被发布出去。最后,组件将自己的原封不动的传递给。但是通过这次的实践,也算是熟悉的的用法,对也加深了了解吧。

这是一篇我发在掘金上的文章,原文有一个我没有解决的问题,在网友的解答下我找到了答案,我把文章重新修改编辑后,同步发送到这里,希望能对大家有所帮助。
本文原发布于掘金:https://juejin.im/post/5a900d...

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

由于是公司的项目,所以下文的示例代码都是我重新写的,望见谅!

基本用法

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

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

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

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

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


    
        {
            context => (
                
name:  {context.name}  age:  {context.age}
) }

ContextProvider作为数据的发布方,它拥有一个名为value的属性,用于维护数据内容,通过value传递给ContextProvider的数据会被发布出去。
而ContextConsumer作为数据的订阅方,它的props.children是一个函数,接收的参数是被发布的数据,我们通过调用这个函数来获取被ContextProvider发布的数据,并且返回我们想要渲染的组件。
在这个示例中,我们最后在页面上能够显示出name: A age: 18

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

const Context = createContext({ gender: "male" });

    
        {
            context => (
                
name:  {context.name}  age:  {context.age}
) }

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

补充

经过网友的解答和我自己的试验,这个问题得到了解答:

Provider的value属性会把初始化Context时传递的初始状态给覆盖掉;

如果想要使用初始的状态,那么就不能使用Provider,也就是说,只有订阅数据而不发布新数据的情况下,初始的状态才会有效;

实践

为了适应项目的需求,我主要是对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 (
      
        {this.props.children}
      
    );
  }
}

MyProvider组件返回的是ContextProvider组件,并把MyProvider的state作为要发布的数据绑定到了ContextProvider的value属性上。
前面讲过,由于其他组件有要修改被发布数据的需求,所以我给数据添加了一个不可修改的方法updateContext,这个方法能够接收新的数据并更新MyProvider的state,即更新了被发布的数据。
最后,MyProvider组件将自己的children原封不动的传递给ContextProvider。

ContextConsumer

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

export const MyConsumer = Component => {
  return props => (
    
      {context => {
        return ;
      }}
    
  );
};

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 (
      
name: {name} age: {age}
); } } 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会更方便和安全。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95115.html

相关文章

  • Why React

    摘要:观察者模式,一次创建多条通信链路,每条链路工作时与其他链路发生干扰。在目前系统中,只存在兄弟通信和父子通信,不存在跨树通信,即孩子不能跟叔叔直接通信。模拟操作的方式,归根到底是把手动测试过程用脚本记录下来。 作者:BrianLi (部门同事李老师,口头授权发布内部react布道资料) 无法用语言准确表达思维时,就用公式;一个不行,那就两个 —— 李老师 本文假设读者已了解react的基...

    JayChen 评论0 收藏0
  • 对服务端渲染一次实践(带你掌握服务端渲染)

    摘要:之前做的一个应用,最近把首页改成了服务端渲染的形式,过程还是很周折的,踩到了不少坑,记录一些重点,希望有所帮助前端使用的技术栈升级到升级到服务项目地址喜欢的给个,感谢。。。。。。。 之前react做的一个应用,最近把首页改成了服务端渲染的形式,过程还是很周折的,踩到了不少坑,记录一些重点,希望有所帮助 前端使用的技术栈 react、react-dom 升级到 v16 react-ro...

    v1 评论0 收藏0
  • 如何优化你的超大型React应用 【原创精读】

    摘要:往往纯的单页面应用一般不会太复杂,所以这里不引入和等等,在后面复杂的跨平台应用中我会将那些技术一拥而上。构建极度复杂,超大数据的应用。 showImg(https://segmentfault.com/img/bVbvphv?w=1328&h=768); React为了大型应用而生,Electron和React-native赋予了它构建移动端跨平台App和桌面应用的能力,Taro则赋...

    cfanr 评论0 收藏0
  • 如何优化你的超大型React应用 【原创精读】

    摘要:往往纯的单页面应用一般不会太复杂,所以这里不引入和等等,在后面复杂的跨平台应用中我会将那些技术一拥而上。构建极度复杂,超大数据的应用。 showImg(https://segmentfault.com/img/bVbvphv?w=1328&h=768); React为了大型应用而生,Electron和React-native赋予了它构建移动端跨平台App和桌面应用的能力,Taro则赋...

    codecook 评论0 收藏0
  • 如何优化你的超大型React应用 【原创精读】

    摘要:往往纯的单页面应用一般不会太复杂,所以这里不引入和等等,在后面复杂的跨平台应用中我会将那些技术一拥而上。构建极度复杂,超大数据的应用。 showImg(https://segmentfault.com/img/bVbvphv?w=1328&h=768); React为了大型应用而生,Electron和React-native赋予了它构建移动端跨平台App和桌面应用的能力,Taro则赋...

    xiguadada 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<