context

定义: Context提供了一种方式,能够让数据在组件树中传递,而不必一级一级手动传递。

API : createContext(defaultValue?)。

使用方法:

首先要引入createContext

import React, { Component, createContext } from 'react';

 然后创建一个Context 

const BatteryContext = createContext();

然后用BatteryContext.Provider包裹组件并且传递属性值。

<BatteryContext.Provider value={60}>
     <Middle />  //子组件
</BatteryContext.Provider>

 为了方便看出效果,将定义一个子组件和一个孙组件。然后不通过子组件,孙组件直接取值

import React, { Component, createContext } from 'react';

const BatteryContext = createContext();

//声明一个孙组件
class Leaf extends Component {
  render() {
    return (
    
    )
  }
}

//声明一个子组件
class Middle extends Component {
  render() {
    return <Leaf /> 
  }
}

class App extends Component {
  render(){
    return (
      <BatteryContext.Provider value={60}>
        <Middle />
      </BatteryContext.Provider>
    );
  }
}

export default App;

孙组件需要BatteryContext.Consumer来接收值,Consumer里面不能直接渲染其他组件,而是要声明一个函数。函数的参数就是context的值。

class Leaf extends Component {
  render() {
    return (
      <BatteryContext.Consumer>
        {
          battery => <h1>Battery : {battery}</h1>
        }
      </BatteryContext.Consumer>
    )
  }
}

 效果图;

React的Context的使用方法简介-编程知识网

这样没通过Middle组件来传递值,但是Leaf组件能通过context来获得属性。这就是context的基本用法。

context不但能跨层级来传递属性值,还能在属性值发生变化的时候重渲染Consumer下面的元素,举个例子:
 
在state中定义battery并赋值

state = {
    battery: 60
  }

然后做一个按钮,每次点击的时候都要battery减一。  代码:

render() {
    const { battery } = this.state;
    return (
      <BatteryContext.Provider value={battery}>
        <button
          type="button"
          onClick={() => this.setState({ battery: battery - 1 })}
        >
          减减
        </button>
        <Middle />
      </BatteryContext.Provider>
    );
  }

全部代码:

import React, { Component, createContext } from 'react';

const BatteryContext = createContext();

//声明一个孙组件
class Leaf extends Component {
  render() {
    return (
      <BatteryContext.Consumer>
        {
          battery => <h1>Battery : {battery}</h1>
        }
      </BatteryContext.Consumer>
    )
  }
}

//声明一个子组件
class Middle extends Component {
  render() {
    return <Leaf />
  }
}

class App extends Component {
  state = {
    battery: 60
  }
  render() {
    const { battery } = this.state;
    return (
      <BatteryContext.Provider value={battery}>
        <button
          type="button"
          onClick={() => this.setState({ battery: battery - 1 })}
        >
          减减
        </button>
        <Middle />
      </BatteryContext.Provider>
    );
  }

}

export default App;

 效果图: 

React的Context的使用方法简介-编程知识网

这样每次点击都会使battery得数值发生变化,从而重渲染Consumer下面的元素。

如果有多个Context该怎么做呢?我们在创建一个 Context

const OnLineContext = createContext();

如果有多个context变量的话,只需要把Privider嵌套进来即可,顺序不重要。接下来声明online的Provider了。

class App extends Component {
  state = {
    battery: 60,
    online: false
  }
  render() {
    const { battery, online } = this.state;
    return (
      <BatteryContext.Provider value={battery}>
        <OnLineContext.Provider value={online} >
          <button
            type="button"
            onClick={() => this.setState({ battery: battery - 1 })}
          >
            减减
        </button>
          <button
            type="button"
            onClick={() => this.setState({ online: !online })}
          >
            Switch
        </button>
          <Middle />
        </OnLineContext.Provider>
      </BatteryContext.Provider>
    );
  }

与Provider类似。Consumer也需要嵌套,顺序不重要。只要Consumer需要声明函数,所以要注意语法。

class Leaf extends Component {
  render() {
    return (
      <BatteryContext.Consumer>
        {
          battery => (
            <OnLineContext.Consumer>
              {
                online => <h1>Battery : {battery} , Online : {online.toString()}</h1>
              }
            </OnLineContext.Consumer>
          )
        }
      </BatteryContext.Consumer>
    )
  }
}

 

 全部代码:

import React, { Component, createContext } from 'react';

const BatteryContext = createContext();
const OnLineContext = createContext();

//声明一个孙组件
class Leaf extends Component {
  render() {
    return (
      //与Provider类似。Consumer也需要嵌套,顺序不重要。只要Consumer需要声明函数,所以要注意语法。
      <BatteryContext.Consumer>
        {
          battery => (
            <OnLineContext.Consumer>
              {
                online => <h1>Battery : {battery} , Online : {online.toString()}</h1>
              }
            </OnLineContext.Consumer>
          )
        }
      </BatteryContext.Consumer>
    )
  }
}

//声明一个子组件
class Middle extends Component {
  render() {
    return <Leaf />
  }
}

class App extends Component {
  state = {
    battery: 60,
    online: false
  }
  render() {
    const { battery, online } = this.state;
    //接下来声明online的Provider了。如果有多个context变量的话,只需要把Privider嵌套进来即可,顺序不重要。
    return (
      <BatteryContext.Provider value={battery}>
        <OnLineContext.Provider value={online} >
          <button
            type="button"
            onClick={() => this.setState({ battery: battery - 1 })}
          >
            减减
        </button>
          <button
            type="button"
            onClick={() => this.setState({ online: !online })}
          >
            Switch
        </button>
          <Middle />
        </OnLineContext.Provider>
      </BatteryContext.Provider>
    );
  }

}

export default App;

效果图:

React的Context的使用方法简介-编程知识网

还有一个问题 , 如果Consumer向上找不到对应的Provider怎么办?
 

其实即使找不到也不会报错,而是显示为空。那怎么设置默认值呢?
 

那上面的demo举例 ,刚才我们设置的battery为60。如果Consumer向上找不到BatteryContext.Provider的值,我们可以这样设置默认值:

const BatteryContext = createContext(30);

这样BatteryContext.Consumer向上找不到值,就会取默认值30。

context不仅仅只是可以传数值,也可以传函数。大家可以试试看。
最后再提示一下大家,不要滥用context,不然会影响组件的独立性。 如果一个组件中只使用一个Context的话,就可以使用contextType代替Consumer。详见https://www.cnblogs.com/littleSpill/p/11221817.html