React Context用法小结(附完整代码)

 更新时间:2023年04月24日 15:49:28   作者:成续源  
这篇文章主要介绍了React Context用法小结(附完整代码),Context提供了一种新的组件之间共享数据的方式,允许数据隔代传递,而不必显式的通过组件树逐层传递props,本文通过示例代码介绍的非常详细,需要的朋友可以参考下

前言

传统的React应用中,数据通过props属性自上而下(由父组件向子组件)传递,当组件层级数量增多时,在每一层传递props则很繁琐,Context提供了一种新的组件之间共享数据的方式,允许数据隔代传递,而不必显式的通过组件树逐层传递props。

根据官网链接对Context常用的5种使用场景进行了整理,并随文配上完整代码。

使用场景:

  • 父组件使用Provider生产数据,子组件使用Consumer消费数据
  • 子组件使用ContextType接收数据
  • 动态和静态Context(父组件更新Context,被Provider包裹的子组件刷新数据,没被Provider包裹的子组件使用Context默认值)
  • 在嵌套组件中更新Context(子组件通过Context传递的函数更新数据)
  • 消费多个Context

知识点汇总

  • 首先创建1个Context对象,当React渲染1个订阅了Context对象的组件,这个组件会从组件树中离自身最近的那个匹配的Provider读取到当前的context值。
  • 每个Context都返回1个React组件,允许消费组件订阅context的变化
  • ContextType只能在类组件中使用
  • 1个组件如果有多个消费者,ContextType支队其中1个有效,也就是ContextType只能有1个(所以推荐使用Provider和Consumer形式)

场景1:使用Provider和Consumer生产和消费数据 文件目录及说明

以下文件在同级路径:

  • ProductContext.js:创建的Context组件文件
  • ProviderPage.js:父组件(数据生产者)
  • MiddlePage.js:中间组件
  • ConsumerPage.js:子组件(数据消费者)

数据传递路径:
ProviderPage.js ==> MiddlePage.js ==> ConsumerPage.js

代码文件 ProductContext.js:

import React from 'react';

// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 创建1个Context对象并给定默认值,如果没有匹配到Provider,消费组件取Context默认值
export const ProductContext = React.createContext({
  name: 'car',
  price: 8000,
  unit: '$',
});

export const { Provider, Consumer } = ProductContext;

ProviderPage.js:

import React, { PureComponent } from 'react';
import MiddlePage from './MiddlePage';

import { Provider } from './ProductContext';


class ProviderPage extends PureComponent {

  state = {
    product: {
      name: 'plane',
      price: 120000,
      unit: '$',
    },
  };
  
  render() {
    const { product } = this.state;

    return (
      <div>
        <h1>根组件使用Provider传值,子组件使用Consumer接收</h1>

        <Provider value={product}>
          <MiddlePage />
        </Provider>
        {/*不用Provider,显示Context对象defaultValue*/}
        {/*   <MiddlePage />*/}
      </div>
    );
  }
}

export default ProviderPage;

MiddlePage.js:

import React, { PureComponent } from 'react';
import ConsumerPage from './ConsumerPage';

class MiddlePage extends PureComponent {

  render() {
    return (
      <ConsumerPage />
    );
  }
}

export default MiddlePage;

ConsumerPage.js:

import React, { PureComponent } from 'react';
import { Consumer } from './ProductContext';


class ConsumerPage extends PureComponent {

  render() {
    return (
      <Consumer>
        {context => {
          return (
            <div>
              name:{context.name}
              <br />
              price:{context.price}
              <br />
              unit:{context.unit}
            </div>
          );
        }}
      </Consumer>
    );
  }
}

export default ConsumerPage;

效果

在这里插入图片描述

可以看到显示的是ProviderPage组件提供的Context值。

场景2:使用ContextType接收数据

文件目录及说明

  • FamilyContext.js:创建的Context组件
  • FatherPage.js:父组件(生产数据)
  • SonPage.js:子组件(中间组件)
  • GrandSonPage.js:孙组件(消费数据)

代码文件

FamilyContext.js

import React, { PureComponent } from 'react';
import SonPage from './SonPage';

import { Provider } from './FamilyContext';


class FatherPage extends PureComponent {

  state = {
    person: {
      name: 'Lora',
      age: 99,
      gender: 'female',
    },
  };


  render() {
    const { person } = this.state;

    return (
      <div>
        <h1>使用ContextType消费Context数据</h1>

        <Provider value={person}>
          <SonPage />
        </Provider>

        {/*不用Provider,显示Context对象defaultValue*/}
        {/*<SonPage />*/}
      </div>
    );
  }
}

export default FatherPage;

SonPage.js:和上面的MiddlePage.js一样

import React, { PureComponent } from 'react';
import GrandSonPage from './GrandSonPage'

class SonPage extends PureComponent {


  render() {

    return (
      <GrandSonPage />
    );
  }
}

export default SonPage;

GrandSonPage.js:使用ContextType接收数据

import React, { PureComponent } from 'react';

import { FamilyContext } from './FamilyContext';


class GrandSonPage extends PureComponent {

  //
  static contextType = FamilyContext;

  componentDidMount() {
    // 使用contexType可以在任意生命周期访问数据
    // 使用 this.context 来消费最近 Context 上的那个值
    const value = this.context;
    console.log(value);
  }

  render() {
    // Context是1个对象,对对象进行解构操作
    const { name, age, gender } = this.context;

    return (
      <div>
        name:{name}
        <br />
        age:{age}
        <br />
        gender:{gender}
      </div>
    );
  }
}

export default GrandSonPage;

效果

在这里插入图片描述

场景3:动态和静态Context

在ProviderPage.js中,被Provider包裹的组件可以更新的Context数据,没被Provider包裹的组件只能获取Context默认值。

代码文件

ProductContext.js

import React from 'react';

// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 创建1个Context对象
// 默认值,如果没有匹配到Provider取默认值
export const ProductContext = React.createContext({
  name: 'car',
  price: 17000,
  unit: '$',
});

export const { Provider, Consumer } = ProductContext;

ProviderPage.js

import React, { PureComponent } from 'react';
import { Button, Divider } from 'antd';
import MiddlePage from './MiddlePage';

import { Provider } from './ProductContext';


class ProviderPage extends PureComponent {

  state = {
    product: {
      name: 'plane',
      price: 120000,
      unit: '$',
    },
  };

  handleChange = () => {
    const { product: { name, price, unit } } = this.state;

    this.setState({
      product: {
        name,
        price: price + 1,
        unit,
      },
    });
  };


  render() {
    const { product } = this.state;

    return (
      <div>
        <h1>父组件更新Context,被Provider包裹的子组件刷新值,没被包裹的子组件使用Context默认值</h1>
        {/*在Provider包裹的内部组件使用state中的值*/}
        <Provider value={product}>
          <MiddlePage />
        </Provider>
        <Divider />
        {/*不在Provider包裹的外部组件使用ProductContext重的默认值*/}
        <MiddlePage />
        <Divider />
        <Button
          onClick={this.handleChange}
          type="primary"
        >
          增加
        </Button>
      </div>
      // {不用Provider,显示Context对象defaultValue
      // <MiddlePage />
    );
  }
}

export default ProviderPage;

MiddlePage.js

import React, { PureComponent } from 'react';
import ConsumerPage from './ConsumerPage';

class MiddlePage extends PureComponent {

  render() {
    return (
      <ConsumerPage />
    );
  }
}

export default MiddlePage;

ConsumerPage.js

import React, { PureComponent } from 'react';
import { Consumer } from './ProductContext';


class ConsumerPage extends PureComponent {


  render() {

    return (
      <Consumer>
        {context => {
          return (
            <div>
              name:{context.name}
              <br />
              price:{context.price}
              <br />
              unit:{context.unit}
            </div>
          );
        }}
      </Consumer>
    );
  }
}

export default ConsumerPage;

效果

在这里插入图片描述

点击增加按钮,上面的price会增加(使用Context更新值),下面的不变(使用Context默认值)。

场景4:在嵌套组件中更新Context

代码文件

ProductContext.js

import React from 'react';

// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 创建1个Context对象
// 注意第1个参数是1个object {}
export const ProductContext = React.createContext({
    product: {
      name: 'car',
      price: 8000,
      unit: '$',
    },

    // 通过context传递1个函数,使得consumer组件更新context
    handlePrice: () => {
    },
  },
);


export const { Provider, Consumer } = ProductContext;

ProviderPage.js

import React, { PureComponent } from 'react';
import MiddlePage from './MiddlePage';

import { Provider } from './ProductContext';


class ProviderPage extends PureComponent {

  state = {
    product: {
      name: 'plane',
      price: 120000,
      unit: '$',
    },
    // state页包含了更新函数,因此会被传递进context provider
    handlePrice: () => this.handlePrice(),
  };

  handlePrice = () => {
    const { product: { name, price, unit } } = this.state;

    this.setState({
      product: {
        name,
        price: price + 1,
        unit,
      },
    });
  };


  render() {
    const { product, handlePrice } = this.state;

    return (
      <div>
        <h1>子组件通过context传递的函数更新context,等于在子组件中更新状态</h1>
        {/*注意此时传递进去的是state,包含product对象和1个函数*/}
        <Provider value={{ product, handlePrice }}>
          <MiddlePage />
        </Provider>
        {/*不用Provider,显示Context对象defaultValue*/}
        {/*   <MiddlePage />*/}
      </div>
    );
  }
}

export default ProviderPage;

MiddlePage.js

import React, { PureComponent } from 'react';
import ConsumerPage from './ConsumerPage';

class MiddlePage extends PureComponent {

  render() {
    return (
      <ConsumerPage />
    );
  }
}

export default MiddlePage;

ConsumerPage.js

import React, { PureComponent } from 'react';
import { Button, Divider } from 'antd';
import { Consumer } from './ProductContext';


class ConsumerPage extends PureComponent {


  render() {
    return (
      <Consumer>
        {/*创建的Context对象*/}
        {/*ConsumerPage组件不仅从context获取product对象值,还获取1个handlePrice函数*/}
        {/*注意参数名要和Provider中传入的以及context中定义的一摸一样*/}
        {context => {
          return (
            <div>
              name:{context.product.name}
              <br />
              price:{context.product.price}
              <br />
              unit:{context.product.unit}
              <Divider />
              <Button
                onClick={context.handlePrice}
                type="primary"
              >
                增加
              </Button>
            </div>
          );
        }}
      </Consumer>
    );
  }
}

export default ConsumerPage;

效果

在这里插入图片描述

增加按钮在子组件ConsumerPage.js中定义,Context传递1个函数给子组件,具体的函数实现在父组件ProviderPage.js中,此处感觉还是类似React回调函数,优势就是中间组件MiddlePage不用传递任何props,包括回调函数。

场景5:消费多个Context

代码文件

MultiContext.js

import React from 'react';
const SchoolContext = React.createContext({
  name: '南师附中',
  location: '南京',
});

const StudentContext = React.createContext({
  name: 'chengzhu',
  age: 17,
});

export { SchoolContext, StudentContext };

ProviderPage.js

import React, { PureComponent } from 'react';
import MiddlePage from './MiddlePage';

import { SchoolContext, StudentContext } from './MultiContext';


class ProviderPage extends PureComponent {

  state = {
    school: {
      name: '清华大学',
      location: '北京',
    },
    student: {
      name: '张云',
      age: 22,
    },
  };


  render() {
    const { school, student } = this.state;

    return (
      <div>
        <h1>消费多个Context</h1>

        <SchoolContext.Provider value={school}>
          <StudentContext.Provider value={student}>
            <MiddlePage />
          </StudentContext.Provider>
        </SchoolContext.Provider>
      </div>

      // 不用Provider包裹显示Context中定义的默认值
      // <MiddlePage />
    );
  }
}

export default ProviderPage;

MiddlePage.js

import React, { PureComponent } from 'react';
import ConsumerPage from './ConsumerPage';

class MiddlePage extends PureComponent {

  render() {
    return (
      <ConsumerPage />
    );
  }
}

export default MiddlePage;

ConsumerPage.js

import React, { PureComponent } from 'react';
import { SchoolContext, StudentContext } from './MultiContext';
class ConsumerPage extends PureComponent {
  render() {

    return (
      <SchoolContext.Consumer>
        {school => (
          <StudentContext.Consumer>
            {student => {
              return (
                <div>
                  就读学校: {school.name}
                  <br />
                  学校位置: {school.location}
                  <br />
                  学生姓名: {student.name}
                  <br />
                  学生年龄: {student.age}
                </div>
              );
            }}
          </StudentContext.Consumer>
        )}
      </SchoolContext.Consumer>
    );
  }
}

export default ConsumerPage;

效果

在这里插入图片描述

可以看到传递了2个Context,分别是SchoolContext和StudentContext,子组件ConsumerPage消费了传递进来的2个Context数据。

到此这篇关于React Context用法小结(附完整代码)的文章就介绍到这了,更多相关React Context用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React-Router如何进行页面权限管理的方法

    React-Router如何进行页面权限管理的方法

    本篇文章主要介绍了React-Router如何进行页面权限管理的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • 解析React ref 命令代替父子组件的数据传递问题

    解析React ref 命令代替父子组件的数据传递问题

    这篇文章主要介绍了React - ref 命令为什么代替父子组件的数据传递,使用 ref 之后,我们不需要再进行频繁的父子传递了,子组件也可以有自己的私有状态并且不会影响信息的正常需求,这是为什么呢?因为我们使用了 ref 命令的话,ref是可以进行状态的传输
    2022-08-08
  • React实践之Tree组件的使用方法

    React实践之Tree组件的使用方法

    本篇文章主要介绍了React实践之Tree组件的使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • React中useState和useEffect的用法详解

    React中useState和useEffect的用法详解

    Hooks 发布之后,函数组件能拥有自己的 state,React提供了很多内置的Hooks,这篇文章就来和大家介绍一下useState 和 useEffect的使用,需要的可以参考一下
    2023-06-06
  • Remix如何支持原生 CSS方法详解

    Remix如何支持原生 CSS方法详解

    这篇文章主要为大家介绍了Remix如何支持原生CSS的方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • React中项目路由配置与跳转方法详解

    React中项目路由配置与跳转方法详解

    这篇文章主要为大家详细介绍了React中项目路由配置与跳转方法的相关资料,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-08-08
  • React中父子组件通信详解

    React中父子组件通信详解

    这篇文章主要介绍了React中父子组件通信详解,在父组件中,为子组件添加属性数据,即可实现父组件向子组件通信,文章通过围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • React教程之Props验证的具体用法(Props Validation)

    React教程之Props验证的具体用法(Props Validation)

    这篇文章主要介绍了React教程之Props验证的具体用法(Props Validation),非常具有实用价值,需要的朋友可以参考下
    2017-09-09
  • 使用 React Router Dom 实现路由导航的详细过程

    使用 React Router Dom 实现路由导航的详细过程

    React Router Dom 是 React 应用程序中用于处理路由的常用库,它提供了一系列组件和 API 来管理应用程序的路由,这篇文章主要介绍了使用 React Router Dom 实现路由导航,需要的朋友可以参考下
    2024-03-03
  • react PropTypes校验传递的值操作示例

    react PropTypes校验传递的值操作示例

    这篇文章主要介绍了react PropTypes校验传递的值操作,结合实例形式分析了react PropTypes针对传递的值进行校验操作相关实现技巧,需要的朋友可以参考下
    2020-04-04

最新评论