[路飞]_React 组件跨层级通信 - Context

649 阅读2分钟

React 组件跨层级通信 - Context

github代码地址

前言:

如果在页面逻辑很远的两个页面需要进行数据传递,我们会怎么办呢?通过props一层一层的向下传递吗?通过全局变量来传递信息吗?

  • 如果使用props中间需要修改是不是每一层都需要修改,而且一层一层的传递工作量也非常大,比较麻烦;

  • 如果使用全局变量来传递信息,我们怎么保证数据更新了,它的子组件刷新呢?如果使用forceUpdate更新组件,很显然就很麻烦,而且全局变量还会造成全局污染;

嗯...孩子大了终究是瞒不住了,接下来我们来介绍一个React组件跨层级通信API context

Context API
  1. 创建一个Context对象

  2. 创建Provider,传递value

  3. 子组件消费value

    1. contextType

      1. 只能用在类组件,只能订阅单一的context来源
    2. useContext

      1. 只能用在函数组件或者自定义hook中
    3. consumer

      1. 不限制函数或者类组件

    // context.js

    import React from "react";

    ​export const Context = React.createContext();

    ​export const UserContext = React.createContext();​

1. contextType
// 父组件 ContextPage.js​
import React, { Component } from "react";
import { Context } from "../context"; // 引入Context对象
import ContextTypePage from "./ContextTypePage"; // 引入子组件​
export default class ContextPage extends Component {  
    constructor(props) {    
        super(props);    
        this.state = {      
            theme: { themeColor: "red" },    
        };  
    }​  
    render() {    
        const { theme, user } = this.state;    
        return (      
            <div>        
                <h3>ContextPage</h3>        
                <Context.Provider value={theme}> // 创建Context.Provider,传递value            
                    <ContextTypePage /> // 调用子组件进行消费value        
                </Context.Provider>      
            </div>    );  
    }
}

​​// 子组件 ContextTypePage.js
import React, { Component } from "react";
import { Context/**UseContext**/ } from "../context";  // 引入Context对象export default class ContextPage extends Component {  
    static contextType = Context; // 使用contextType    
    // 因为contextType只能订阅单一的context来源,所以我们在这里再获取一个UseContext的话,Context将失效  
    // static contextType = UseContext;    

    render() {    
        const { themeColor } = this.context;​    
        return (      
            <div>        
                <h3 className={themeColor}>ContextTypePage</h3>      
            </div>    
        );  
    }
}​
2. useContext
// 父组件 ContextPage.js

import React, { Component } from "react";
import { Context, UserContext } from "../context"; // 引入Context对象和UserContext对象
import ContextTypePage from "./ContextTypePage"; // 引入子组件
import UseContextPage from "./UseContextPage"; // 引入子组件

export default class ContextPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      theme: { themeColor: "red" },
      user: { name: "xiaoming" },
    };
  }

  render() {
    const { theme, user } = this.state;
    return (
      <div>
        <h3>ContextPage</h3>
        <Context.Provider value={theme}>
          <UserContext.Provider value={user}>  // UserContext.Provider,传递value
            <ContextTypePage />
            <UseContextPage /> // 消费子组件
          </UserContext.Provider>
        </Context.Provider>
      </div>
    );
  }
}


// 子组件 UseContextPage.js

import React from "react";
import { Context, UserContext } from "../context";

export default function UseContextPage(props) { // 只能在函数组件中或者自定义hook中使用
  // 可以多个订阅
  const theme = React.useContext(Context);
  const user = React.useContext(UserContext);

  return (
    <div>
      <h3 className={theme.themeColor}>UseContextPage</h3>
      <p>{user.name}</p>
    </div>
  );
}

3. consumer
// 父组件 ContextPage.js

import React, { Component } from "react";
import { Context, UserContext } from "../context";
import ContextTypePage from "./ContextTypePage";
import UseContextPage from "./UseContextPage";
import ConsumerPage from "./ConsumerPage"; // 引入子组件

export default class ContextPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      theme: { themeColor: "red" },
      user: { name: "xiaoming" },
    };
  }

  render() {
    const { theme, user } = this.state;
    return (
      <div>
        <h3>ContextPage</h3>
        <Context.Provider value={theme}>
          <UserContext.Provider value={user}>
            <ContextTypePage />
            <UseContextPage />
            <ConsumerPage /> // 子组件消费value
          </UserContext.Provider>
        </Context.Provider>
      </div>
    );
  }
}


// 子组件 ConSumerPage.js
import React, { Component } from "react";
import { Context, UserContext } from "../context";

export default class ConsumerPage extends Component {
  render() {
    return (
      <div>
        <h3>ContextPage</h3>
        <Context.Consumer> // 创建Context.Consumer对象
          {(theme, user) => {
            return (
              <div className={theme.themeColor}>
                <UserContext.Consumer>
                  {(user) => {
                    return <div>{user.name}</div>;
                  }}
                </UserContext.Consumer>
              </div>
            );
          }}
        </Context.Consumer>
      </div>
    );
  }
}