react context

首先创建4个函数,f1(),f2(),f3(),f4()

function f1() {
  console.log('f1')
}

function f2() {
  console.log('f2')
}

function f3() {
  console.log('f3')
}

function f4() {
  console.log('f4')
}
f1() 
console.log('have done')

然后我们在f1中调用f2, f2中调用f3,f3中调用f4

function f1() {
  console.log('f1')
  f2()
}

function f2() {
  console.log('f2')
  f3()
}

function f3() {
  console.log('f3')
  f4()
}

此时我们可以看到f1,f2,f3,f4逐层调用了。<br />
image.png
image.png

此时我们有一个场景,需要在这个调用顺序下,让f1传值给f4<br />先给f1调用的地方创建作用域

{
  let num = 1000;
  f1(num);
  console.log("have done");
}

之后我们将值进行逐层传递

function f1(n1) {
  console.log("f1", n1);
  f2(n1);
}

function f2(n2) {
  console.log("f2", n2);
  f3(n2);
}

function f3(n3) {
  console.log("f3", n3);
  f4(n3);
}

function f4(n4) {
  console.log("f4", n4);
}

之后我们就把num=1000,传递给了f4函数<br />
image.png
image.png

接下来我们把这个思路,应用到react组件中。首先创建F1,F2,F3,F4四个组件

function F1() {
  return (
    <div>
      1 <F2 />
    </div>
  );
}
function F2() {
  return (
    <div>
      2 <F3 />
    </div>
  );
}
function F3() {
  return (
    <div>
      3 <F4 />
    </div>
  );
}
function F4() {
  return <div>4 </div>;
}
function App() {
  return (
    <div className="App">
      <F1 />
    </div>
  );
}

然后重复之前的逻辑,将值通过props逐层传递<br />首先给App组件添加useState

function App() {
  const num = useState(111)[0];
  return (
    <div className="App">
      <F1 n1={num} />
    </div>
  );
}

之后给每个组件添加props并传递下去

function F1({ n1 }) {
  return (
    <div>
      1 , {n1}
      <F2 n2={n1} />
    </div>
  );
}
function F2({ n2 }) {
  return (
    <div>
      2 ,{n2}
      <F3 n3={n2} />
    </div>
  );
}
function F3({ n3 }) {
  return (
    <div>
      3 ,{n3}
      <F4 n4={n3} />
    </div>
  );
}
function F4({n4}) {
  return <div>4 , {n4}</div>;
}

此时我们顺利将值111传递到了F4组件<br />
image.png
image.png

<br />在这个作用域中,F4组件只能逐层接受来自F1->F2->F3的值。

之前我们通过逐层传值的方式,将num从f1传递到了f4,但是这么麻烦,假如直接把值存放在f4的作用域外面呢

let num = 100
function f1(n1) {
  console.log("f1", n1);
  f2(n1);
}

function f2(n2) {
  console.log("f2", n2);
  f3(n2);
}

function f3(n3) {
  console.log("f3", n3);
  f4(n3);
}

function f4(n4) {
  console.log("f4", num);
}
{
  f1()
}

此时,f4可以直接访问到num<br />


image.png
image.png

此时,作为一个全局变量num,访问非常不安全

num = 55
function f4(n4) {
  console.log("f4", num);
}
{
  f1()
}

或者将f1在setTimeout中调用

{
  setTimeout(()=>{
    f1()
  },1000)

  num = 222
}
image.png
image.png

num作为全局变量范围太广,逻辑复杂后无法控制,很有可能拿到的不是你所想要的值,一般不推荐使用。<br />因此,我们需要一个范围大一些的局部变量。

{
  let context = {
    num:100
  };
  function f1() {
    console.log("f1");
    f2();
  }
  
  function f2() {
    console.log("f2");
    f3();
  }
  
  function f3() {
    console.log("f3");
    f4();
  }
  function f4(n4) {
    console.log("f4", context.num);
  }
}

在这个作用域中,都可以访问context.num,但是此时外部是无法访问这个的.

因此,在那个作用域中,我们应该给外面暴露一个set方法

window.setContext = (key,value)=>{
    context[key] = value
  }
{
  window.setContext("num", 300);
  setTimeout(() => {
    window.f1();
  }, 1000);
}

我们达到了f4访问context.num的作用,并且只能通过setContext方法改变值

通过闭包的方式保护了num的值。<br />react中的context也是同样造了一个局部组件能访问的变量。<br />首先声明一个context

const ThemeContext = React.createContext('light')

然后在App中调用context.Provider, 最里层组件调用Consumer

class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="red">
        <div className="App">
          <ToolBar />
        </div>
      </ThemeContext.Provider>
    );
  }
}
function ThemeButton(props) {
  return (
    <ThemeContext.Consumer>
      {theme => <Button theme={theme} />}
    </ThemeContext.Consumer>
  );
}

此时,我们顺利得让ThemeButton访问到了来自App的theme= 'red'

react context (provider和consumer)

之前,我们顺利的在consumer中拿到了provider传递过来的值。但是在consumer中不同于provider,我们需要在函数中拿到这个值。

[图片上传中...(image.png-db2c62-1601778823071-0)]

先使用babel下

React.createElement(ThemeContext.Consumer, null, function (theme) {
  return React.createElement(Button, {
    theme: theme
  });
});

可以清晰的看出,事实上相当于创建了一个新的标签,然后将值传递给了<Button/>

function F1 () {
  return 'function1'
  
}

<ThemeContext.Consumer>
      {(theme) => <Button theme={theme} />}
   F1
  {F1}
  <F1/>
</ThemeContext.Consumer>
function F1() {
  return 'function1';
}

React.createElement(ThemeContext.Consumer, null, function (theme) {
  return React.createElement(Button, {
    theme: theme
  });
}, "F1", F1, React.createElement(F1, null));

F1是字符串'F1', {F1}是F1函数未被调用,可通过props.children访问, <F1/>才会最终渲染。<br />事实上,consumer相当于return了props.children(),然后将其渲染在组件上。<br />我们来创建一个自己的Consumer,然后在父组件App()中调用

function Consumer(props) {
  let x = 100;
  let result = props.children(x);
  return <div>{result}</div>;
}
function App() {
  return <Consumer>{n => <div>{n}</div>}</Consumer>;
}

此时result拿到props.children(100)的值,然后挂在在<Consumer />

更新context的值

首先创建4个组件,挂载在App上

function F1() {
  return (
    <div className="bordered">
      111
      <F2 />
    </div>
  );
}
function F2() {
  return (
    <div className="bordered">
      222,
      <F3 />
    </div>
  );
}
function F3() {
  return (
    <div className="bordered">
      333,
      <F4 />
    </div>
  );
}
function F4() {
  return <div className="bordered">444</div>;
}
class App extends React.Component {
  render() {
    return (
      <div className="App">
        <F1 />
      </div>
    );
  }
}

.bordered {
  border: 1px solid #666;
  margin:5px;
}
image.png
image.png

<br />然后创建一个nContext,并将App的state中的值传递给nContext


const nContext = React.createContext(null);
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      num: 100
    };
  }
  render() {
    const { num } = this.state;
    return (
      <div className="App">
        <nContext.Provider value={num}>
          <F1 />
        </nContext.Provider>
      </div>
    );
  }
}

然后将consumer包裹在F4上面,将值传给F4的props

function F3() {
  return (
    <div className="bordered">
      333,
      <nContext.Consumer>
        {
          value=><F4 num={value}/>
        }
      </nContext.Consumer>
      
    </div>
  );
}
function F4(props) {
  return <div className="bordered">444,{props.num}</div>;
}

此时,F4收到了来自顶层的num=100


image.png

我们来创个update函数,然后随一个object传递给F4,这样F4就可以更新值了

function F3() {
  return (
    <div className="bordered">
      333,
      <nContext.Consumer>
        {value => <F4 num={value.num} update={value.update} />}
      </nContext.Consumer>
    </div>
  );
}
function F4(props) {
  return (
    <div className="bordered">
      444,{props.num}
      <button onClick={props.update}>click</button>
    </div>
  );
}
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      num: 100
    };
  }
  updateNum = () => {
    this.setState({
      num: 200
    });
  };
  render() {
    const { num } = this.state;
    let value = {
      num,
      update: this.updateNum
    };
    return (
      <div className="App">
        <nContext.Provider value={value}>
          <F1 />
        </nContext.Provider>
      </div>
    );
  }
}

此时,点击F4中的button,可以看到num变为200了<br />


image.png
image.png
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容