React.createContex的用法

在线代码https://codesandbox.io/embed/myp00yr1xx?fontsize=14
在线演示https://myp00yr1xx.codesandbox.io/react-context

当某个属性需要传递很多层组件才到目标位置时,我们可以使用React.createContext。

我们先来看看使用props层层传递的方式,a,b的传入路径
a -》A-》B1-》C1
b-》A-》B2-》C2

// WithoutContext.js
import React from "react";

export default class App extends React.PureComponent {
  state = {
    a: "aaaaaa",
    b: "bbbbbb"
  };
  render() {
    return <A a={this.state.a} b={this.state.b} />;
  }
}

const A = props => {
  return (
    <>
      <B1 a={props.a} />
      <B2 b={props.b} />
    </>
  );
};

const B1 = props => {
  return <C1 a={props.a} />;
};

const B2 = props => {
  return <C2 b={props.b} />;
};

const C1 = props => (
  <div>
    this is without context passs ---- <strong>{props.a}</strong>
  </div>
);
const C2 = props => (
  <div>
    this is without context passs ---- <strong>{props.b}</strong>
  </div>
);

使用React.createContext的方式

// WithContext.js
import React from "react";

// 初始化Context,并赋予是默认值
const myContext = React.createContext({ a: "默认值a", b: "默认值b" });
const myContext2 = React.createContext("使用多重context");
export default class App extends React.PureComponent {
  state = {
    a: "aaaaaa",
    b: "bbbbbb"
  };
  render() {
    return (
      <myContext.Provider value={this.state}>
        <div
          style={{
            margin: "20px 20px",
            padding: "10px 10px",
            border: "1px solid red"
          }}
        >
          <h4>修改b的值</h4>
          <input onChange={e => this.setState({ b: e.target.value })} />
        </div>
        <A />
        <div
          style={{
            margin: "20px 20px",
            padding: "10px 10px",
            border: "1px solid red"
          }}
        >
          <h4>多重context</h4>
          <myContext2.Provider value="mutiple context--- myContext2">
            <A2 />
          </myContext2.Provider>
        </div>
      </myContext.Provider>
    );
  }
}

const A = () => {
  return (
    <>
      <B1 />
      <B2 />
      <C3 />
      <C4 />
    </>
  );
};

const A2 = () => <B3 />;

const B1 = () => {
  return (
    <myContext.Provider value={{ a: "from B1 Provider" }}>
      <C1 />
    </myContext.Provider>
  );
};

const B2 = () => {
  return <C2 />;
};

const B3 = () => <C5 />;

class C1 extends React.Component {
  // 接收最近的父元素的myContext.Provider中的值,因此这里将接收到B1的值
  static contextType = myContext;
  render() {
    return (
      <div
        style={{
          margin: "20px 20px",
          padding: "10px 10px",
          border: "1px solid gray"
        }}
      >
        <h4>从最近的父元素的Provider取值</h4>
        this is with context pass ----
        <strong>{(this.context || {}).a || ""}</strong>
      </div>
    );
  }
}

class C2 extends React.Component {
  // 接收最近的父元素的myContext.Provider中的值,因此这里将接收到App的值
  // 这里不能随意命名,使用context里的值时,用this.context
  static contextType = myContext;
  render() {
    return (
      <div
        style={{
          margin: "20px 20px",
          padding: "10px 10px",
          border: "1px solid green"
        }}
      >
        <h4>以contextType方式从context中取值</h4>
        this is with context pass ----
        <strong>{(this.context || {}).b || ""}</strong>
      </div>
    );
  }
}

const C3 = () => {
  // 我们也可以通过context.Consumer的方式来接收context里面的value
  // 这时候需要用render prop的方式来使用
  return (
    <div
      style={{
        margin: "20px 20px",
        padding: "10px 10px",
        border: "1px solid green"
      }}
    >
      <h4>以Consumer方式从context中取值</h4>
      <myContext.Consumer>
        {value => (
          <div>
            this is with context pass and accept the value with
            myContext.Consumer----
            <strong>{(value || {}).b || ""}</strong>
          </div>
        )}
      </myContext.Consumer>
    </div>
  );
};

class C4 extends React.Component {
  // 若子组件接收了context,则一旦contex的value发生变化,
  //即使子组件用shouldComponentUpdate限制了更新操作,子组件依然会发生更新
  static contextType = myContext;
  shouldComponentUpdate() {
    return false;
  }
  render() {
    return (
      <div
        style={{
          margin: "20px 20px",
          padding: "10px 10px",
          border: "1px solid blue"
        }}
      >
        <h4>验证使用contex对子组件的更新的影响</h4>
        <p>Call shouldComponentUpdate will always return false.</p>
        <p>But the value updated.</p>
        <div>
          this is with context pass ----
          <strong>{(this.context || {}).b || ""}</strong>
        </div>
      </div>
    );
  }
}

class C5 extends React.Component {
  // 在一个子组件中接收多个contex中的value时,由于一个类只能有一个contextType,所以不能用contextType方式接收
  render() {
    return (
      <myContext.Consumer>
        {context1 => (
          <>
            <div>
              This is the 1st context --- <strong>{(context1 || {}).b}</strong>
            </div>
            <myContext2.Consumer>
              {context2 => (
                <div>
                  This is the 2nd context --- <strong>{context2}</strong>
                </div>
              )}
            </myContext2.Consumer>
          </>
        )}
      </myContext.Consumer>
    );
  }
}

React.createContext使用总结

  1. React.createContext(initialValue),赋予初始值后,若子组件在接收了context的,但是在其父组件中并未使用context,这时候context的值为默认值。
  2. 赋值方式
   <myContext.Provider value={youValue}>
   ...
   </myContext.Provider value={youValue}>
  1. 接收context的2种方式: contextType和Consumer
static contextType = myContext;
...
<strong>{(this.context || {}).b || ""}</strong>
   <myContext2.Consumer>
   		{ value => <Component propName={value} /> }
   </myContext2.Consumer>
  1. 使用context传值后,若子组件接收了context的值,若context的发生了变化,即使shouldComponentUpdate返回false,子组件也会发生更新。
  2. 子组件会就近的接收父组件种对应context.Provider中的值。
  3. 同一子组件若要接收多个context,可以使用Consumer方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值