React入门 7:React Context API

作者: JaniceZD | 来源:发表于2019-10-03 17:34 被阅读0次

    1. 四层函数传递值

    • 原生JS的做法:
    function f1(n1) {
      console.log(1, n1);   // , 是分隔符哦,不会打印出来
      f2(n1);
    }
    function f2(n2) {
      console.log(2, n2);
      f3(n2);
    }
    function f3(n3) {
      console.log(3, n3);
      f4(n3);
    }
    function f4(n4) {
      console.log(4, n4);
    }
    {
      let n = 100;
      f1(n);
      console.log("done");   // f1 全部四层函数执行完毕后才打印 done
    }
    //1 100
    //2 100
    //3 100
    //4 100
    //done
    
    • 使用 React 改写
    function F1(props) {
        return(
          <div>
            1, {props.n1}
            <F2 n2={props.n1} />
          </div>
        )
    }
    function F2(props) {
        return(
          <div>
            2, {props.n2}
            <F3 n3={props.n2} />
          </div>
        )
    }
    function F3(props) {
        return(
          <div>
            3, {props.n3}
            <F4 n4={props.n3} />
          </div>
        )
    }
    function F4(props) {
        return(
          <div>
            4, {props.n4}
          </div>
        )
    }
    
    class App extends React.Component {
      constructor(){
        super()
        this.state ={
          n: 100
        }
      }
      render(){
        return(
          <div>
            <F1 n1={this.state.n}/>
          </div>
        )
      }
    }
    
    ReactDOM.render(<App />, document.querySelector('#app'))
    

    能否直接将 n 传到 f4 ,而不需要通过 f1f2f3层层传递?

    2. 你说使用全局变量?

    • 使用全局变量不安全,随处可改
      全局变量慎用
    • 做个约定:传一个局部的全局变量
      ① ES5 里造一个局部变量,要用立即执行函数 !function() {}()
      ② ES6里造局部变量:{ }
      改写原生JS代码:
      let 声明了一个局部的全局变量
    {
      let context= {}           //context 就是局部的全局变量,其他地方访问不了(闭包)
      window.setContext = function(key,value){
        context[key] = value
      }
      window.f1 = function f1() {
        console.log(1)
        f2()
      }
      function f2() {
        console.log(2)
        f3()
      }
      function f3() {
        console.log(3)
        f4()
      }
      function f4() {
        console.log(4, context['n'])
      }
    }
    
    window.setContext('n', 100)    //设置context
    window.f1()
    
    • 在 React 中使用 Context API

    看看官方文档对 Context 的定义:

    在一个典型的 React 应用中,数据是通过 props 属性由上向下(由父及子)的进行传递的,但这对于某些类型的属性而言是极其繁琐的(例如:地区偏好,UI主题),这是应用程序中许多组件都所需要的。 Context 提供了一种在组件之间共享此类值的方式,而不必通过组件树的每个层级显式地传递 props

    React改写的版本:

    const nContext = React.createContext();
    
    function F1(props) {
      return (
        <div className="bordered">
          1
          <F2 />
        </div>
      );
    }
    function F2(props) {
      return (
        <div className="bordered">
          2
          <F3 />
        </div>
      );
    }
    function F3(props) {
      return (
        <div className="bordered">
          3
          <nContext.Consumer>
            {x => <F4 n4={x} />}
          </nContext.Consumer>
        </div>
      );
    }
    function F4(props) {
      return <div className="bordered">4, {props.n4} </div>;
    }
    
    class App extends React.Component {
      render() {
        return (
          <div>
            <nContext.Provider value="100">
              <F1 />
            </nContext.Provider>
          </div>
        );
      }
    }
    

    3. 标签里居然可以传函数

    注意: 你写的代码不是 html

      <div className="bordered">
          3333
          <nContext.Consumer>
            {(x) => <F4 n4={x}/>}
          </nContext.Consumer>
       </div>
    

    babel在线转换后,代码是这样的:

    React.createElement("div", { className: "bordered" }, 
      "3333",
      React.createElement(nContext.Consumer, null, function (x) {
        return React.createElement(F4, {
          n4: x 
        });
      })
    );
    

    这才是你写的代码的真实模样 : )

    解释一下标签可以传函数:

    function Consumer(props) {
      let x = 100;
      let result = props.children(x);
      return <div>{result}</div>;
    }
    
    function F4(n) {
      return <div>{n}</div>;
    }
    
    function App() {
      return (
        <div className="App">
          <Consumer>
            {F4}
          </Consumer>
        </div>
      );
    }
    
    • {F4}<Consumer>里, 其实返回的是 F4 这个函数。(不是函数运行后的结果)
    • 在组件 Consumer 里,可以用 props.children 获取 这个函数
    • Consumer函数里,执行 props.children(x),同时传入函数 x ,返回的是 F4 函数的返回值。

    简化代码:

    function Consumer(props) {
      let x = 100;
      let result = props.children(x);
      return <div>{result}</div>;
    }
    
    function App() {
      return <Consumer>{n => <div>{n}</div>}</Consumer>;
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    4. 更新 Context 里的值

    如何让 F4 自己来改变这个值 => 把值和方法都放到 this.state 里面,然后传给nContext.Providervalue

    const nContext = React.createContext();
    
    function F1(props) {
      return (
        <div className="bordered">
          1
          <F2 />
        </div>
      );
    }
    function F2(props) {
      return (
        <div className="bordered">
          2
          <F3 />
        </div>
      );
    }
    function F3(props) {
      return (
        <div className="bordered">
          3
          <nContext.Consumer>
            {x => <F4 n4={x.n} setN={x.setN} />}
          </nContext.Consumer>
        </div>
      );
    }
    function F4(props) {
      return (
        <div className="bordered">
          4, {props.n4}
          <button onClick={props.setN}>change</button>
        </div>
      );
    }
    
    class App extends React.Component {
      constructor() {
        super();
        this.state = {
          x: {
            n: 100,
            setN: () => {
              this.setState({
                x: {
                  ...this.state.x,   //es6 扩展运算符语法,除了n之外的setN也要保留下来
                  n: this.state.x.n - 1
                }
              });
            }
          }
        };
      }
      render() {
        return (
          <div>
            <nContext.Provider value={this.state.x}>
              <F1 />
            </nContext.Provider>
          </div>
        );
      }
    }
    

    结合我上篇文章的 React入门 6:Redux 是什么 来看,有没觉得 Context 很像 React-Redux 里的 <Provider>,: )

    相关文章

      网友评论

        本文标题:React入门 7:React Context API

        本文链接:https://www.haomeiwen.com/subject/omkdpctx.html