React Context(执行上下文)

一、Context 解决什么问题

React是单向数据流,数据是从上往下单向传递的,每个组件都可以接收父组件的属性和状态,也可以把属性和状态向下传递给子组件,但是当层级特别多的时候就会变得非常繁琐。Context 提供了一种在组件之间共享此类值得方式,而不必逐层传递。它主要是用来解决祖先组件后代组件传递数据的问题(prop drilling)。方便组件之间跨层级传递数据。

举个例子:用户登录之后,很多组件需要拿到用户相关信息,如果按照prop传递的方式获取,会变得异常繁琐,而且很难判断数据的真正来源。使用Context,就可以在Provider的后代组件的任意位置,都可以Consumer数据。

二、如何使用

  • 1. 通过createContext创建Context
  • 2. 使用Context.Provider组件发布数据(通过给Context.Provider传递value属性)。
  • 3. 如果是函数组件,那么所有后代组件,都可以通过Context.Consumer消费数据
  • 4. 如果是类组件,那么所有的后代组件都需要通过  this.context.xxx 来获取

1.类组件的context

import React from "react";
import ReactDOM from "react-dom";

let ThemeContext = React.createContext();

class Content extends React.Component {
  //取父组件传递过来得值
  //先定义一个静态属性contextType 通过this.context.color拿到值
  static contextType = ThemeContext
  render() {
    return <div style={{ border: `1px solid ${this.context.color}` }}>内容</div>;
  }
}
class Main extends React.Component {
  //取父组件传递过来得值
  //先定义一个静态属性contextType 通过this.context.color拿到值
  static contextType = ThemeContext
  render() {
    return (
      <div style={{ border: `1px solid ${this.context.color}` }}>
        子Main
        <Content}></Content>
      </div>
    );
  }
}
class Title extends React.Component {
  //取父组件传递过来得值
  //先定义一个静态属性contextType 通过this.context.color拿到值
  static contextType = ThemeContext
  render() {
    return <div style={{ border: `1px solid ${this.context.color}` }}>标题</div>;
  }
}
class Header extends React.Component {
  //取父组件传递过来得值
  //先定义一个静态属性contextType 通过this.context.color拿到值
  static contextType = ThemeContext
  render() {
    return (
      <div style={{ border: `1px solid ${this.context.color}` }}>
        子Header
        <Title></Title>
      </div>
    );
  }
}
class Panel extends React.Component {
  state = { color: "green" };
  render() {
    let colorvalue = { color: this.state.color };
    // Provider 表示提供者,负责向下层所有得组件提供数据value 它得所有子组件都可以通过拿到value值
    return (
      <ThemeContext.Provider value={colorvalue}> 
        <div style={{ border: `1px solid ${this.state.color}`, width: `200px` }}>
          Panel
          <Header></Header>
          <Main></Main>
        </div>
      </ThemeContext.Provider>
    );
  }
}

ReactDOM.render(<Panel></Panel>, document.getElementById("root"));

修改数据:

import React from "react";
import ReactDOM from "react-dom";

let ThemeContext = React.createContext();

class Content extends React.Component {
  //取父组件传递过来得值
  //先定义一个静态上下文类型contextType 通过this.context.value拿到值
  static contextType = ThemeContext
  render() {
    return (
    <div style={{ border: `1px solid ${this.context.color}` }}>
      内容
      <button onClick={() => this.context.changeColor('red')}>变红</button>
      <button onClick={() => this.context.changeColor('green')}>变绿</button>
      </div>
      )
  }
}
class Main extends React.Component {
  //取父组件传递过来得值
  //先定义一个静态上下文类型contextType 通过this.context.value拿到值
  static contextType = ThemeContext
  render() {
    return (
      <div style={{ border: `1px solid ${this.context.color}`}}>
        子Main
        <Content style={{ border: `1px solid ${this.context.color}` }}></Content>
      </div>
    );
  }
}
class Title extends React.Component {
  //取父组件传递过来得值
  //先定义一个静态上下文类型contextType 通过this.context.value拿到值
  static contextType = ThemeContext
  render() {
    return <div style={{ border: `1px solid ${this.context.color}` }}>标题</div>;
  }
}
class Header extends React.Component {
  //取父组件传递过来得值
  //先定义一个静态上下文类型contextType 通过this.context.value拿到值
  static contextType = ThemeContext
  render() {
    return (
      <div style={{ border: `1px solid ${this.context.color}` }}>
        子Header
        <Title></Title>
      </div>
    );
  }
}
class Panel extends React.Component {
  state = { color: "green" };
  changeColor = (color) => {
    this.setState({color})
  }
  render() {
    let colorvalue = { color: this.state.color, changeColor: this.changeColor };
    // Provider 表示提供者,负责向下层所有得组件提供数据value 它得所有子组件都可以通过拿到value值
    return (
      <ThemeContext.Provider value={colorvalue}> 
        <div style={{ border: `1px solid ${this.state.color}`, width: `200px` }}>
          Panel
          <Header></Header>
          <Main></Main>
        </div>
      </ThemeContext.Provider>
    );
  }
}

ReactDOM.render(<Panel></Panel>, document.getElementById("root"));

   

任何一个后代组件都可以修改数据,这会导致所有的后代组件都会获取到修改后的值,这显然是不可取的,最好还是由发布者修改。

2.函数组件的context

import React from "react";
import ReactDOM from "react-dom";

let ThemeContext = React.createContext();


function Content (props){
  //Consumer 消费者 消费上下文中的value,通过value.xxx来获取发布的数据
  return (
    <ThemeContext.Consumer>
      {
        (value) => (
          <div style={{ border: `1px solid ${value.color}` }}>
            内容
            <button onClick={() => value.changeColor('red')}>变红</button>
            <button onClick={() => value.changeColor('green')}>变绿</button>
          </div>
        )
      }
    </ThemeContext.Consumer>
  )
}

function Main (props){
  //Consumer 消费者 消费上下文中的value,通过value.xxx来获取发布的数据
  return (
    <ThemeContext.Consumer>
      {
        (value) => (
          <div style={{ border: `1px solid ${value.color}`}}>
            子Main
            <Content style={{ border: `1px solid ${value.color}` }}></Content>
          </div>
        )
      }
    </ThemeContext.Consumer>
  )
}

function Title (props){
  //Consumer 消费者 消费上下文中的value,通过value.xxx来获取发布的数据
  return (
    <ThemeContext.Consumer>
      {
        (value) => (
          <div style={{ border: `1px solid ${value.color}` }}>标题</div>
        )
      }
    </ThemeContext.Consumer>
  )
}
function Header (props){
  //Consumer 消费者 消费上下文中的value,通过value.xxx来获取发布的数据
  return (
    <ThemeContext.Consumer>
      {
        (value) => (
          <div style={{ border: `1px solid ${value.color}` }}>
            子Header
            <Title></Title>
          </div>
        )
      }
    </ThemeContext.Consumer>
  )
}

class Panel extends React.Component {
  state = { color: "green" };
  changeColor = (color) => {
    this.setState({color})
  }
  render() {
    let colorvalue = { color: this.state.color, changeColor: this.changeColor };
    // Provider 表示提供者,负责向下层所有得组件提供数据value 它得所有子组件都可以通过拿到value值
    return (
      <ThemeContext.Provider value={colorvalue}> 
        <div style={{ border: `1px solid ${this.state.color}`, width: `200px` }}>
          Panel
          <Header></Header>
          <Main></Main>
        </div>
      </ThemeContext.Provider>
    );
  }
}

ReactDOM.render(<Panel></Panel>, document.getElementById("root"));

可以看到函数组件需要通过context.Consumer来消费上下文中的value,并且通过value.xxx来获取发布的数据

三、context的底层实现原理

待补充。。。。

猜你喜欢

转载自www.cnblogs.com/lyt0207/p/12688874.html
今日推荐