聊一聊如何使用context,这是学习redux源码的基础哦

在学习redux源码一段时间之后,我发现不懂得context如何使用已经阻碍到我理解redux的设计思想了。。
所以,这里介绍一下react的context如何使用,不过这个api可能你在业务开发时永远不会用到。。
好了,废话不多说,我们来讲解下context如何使用。

一. 如何使用context?

想象一下,我们有现在这样一个页面(Index),其组件树长成如下这个样子:
在这里插入图片描述
假设这个组件树里的任意一个组件都可以去更新Index中的属性themeColor,这个时候就有了状态提升的问题,需要把状态提升到Index中,然后一级一级传下来。
在这里插入图片描述
这里的问题是非常明显的,需要把状态一级一级传递下去,如果组件层次很深的话,可维护性会非常非常差,简直就是灾难。
如果这棵组件树长这个样子就好了,所有组件可以去一个公共区域去获取状态,这样不管组件层次有多深,每个组件都可以去这个公共区域去获取状态。
在这里插入图片描述
我们实现一下这个组件树

class Index extends Component {
  render () {
    return (
      <div>
        <Header />
        <Main />
      </div>
    )
  }
}

class Header extends Component {
  render () {
    return (
    <div>
      <h2>This is header</h2>
      <Title />
    </div>
    )
  }
}

class Main extends Component {
  render () {
    return (
    <div>
      <h2>This is main</h2>
      <Content />
    </div>
    )
  }
}

class Title extends Component {
  render () {
    return (
      <h1>React.js 小书标题</h1>
    )
  }
}

class Content extends Component {
  render () {
    return (
    <div>
      <h2>React.js 小书内容</h2>
    </div>
    )
  }
}

ReactDOM.render(
  <Index />,
  document.getElementById('root')
)

接下来我们基于以上代码,来介绍如何使用context。

class Index extends Component {
  static childContextTypes = {
    themeColor: PropTypes.string
  }

  constructor () {
    super()
    this.state = { themeColor: 'red' }
  }

  getChildContext () {
    return { themeColor: this.state.themeColor }
  }

  render () {
    return (
      <div>
        <Header />
        <Main />
      </div>
    )
  }
}

先声明一个静态变量childContextTypes,这个变量名是固定的。然后,我们在state里初始化一个状态,然后在getChildContext(这个方法名也是固定的)里设置context
以上操作,我们就完成了父组件的context设置工作,接下来,我们看下在子组件里如何去取context

class Title extends Component {
  static contextTypes = {
    themeColor: PropTypes.string
  }

  render () {
    return (
      <h1 style={{ color: this.context.themeColor }}>React.js 小书标题</h1>
    )
  }
}

子组件要想获得context,必须要声明contextTypes,这个变量名也是固定的,必须要这样写。
接下来,我们就可以在子组件中通过this.context来获取context中的值,可以在父组件中通过this.setState来修改context中的值。

二. 更直观地使用context

在最近几个版本中,React对contextapi进行了调整,更加明确了生产者消费者的使用方式。

import React from 'react';

const ThemeContext = React.createContext({
  themeColor: 'red',
});

通过静态方法React.createContext创建一个context对象,这个context对象包含两个组件:ProviderConsumer

class App extends React.Component {
  render () {
    return (
      <ThemeContext.Provider value={{themeColor: 'green'}}>
        <Header />
      </ThemeContext.Provider>
    );
  }
}

Providervalue相当于getChildContext()

class Header extends React.Component {
  render () {
    return (
      <Title>Hello React Context API</Title>
    );
  }
}
 
class Title extends React.Component {
  render () {
    return (
      <ThemeContext.Consumer>
        {context => (
          <h1 style={{background: context.themeColor}}>
            {this.props.children}
          </h1>
        )}
      </ThemeContext.Consumer>
    );
  }
}

Consumerchildren必须是一个函数,通过函数的参数获取Provider提供的Context

三. 总结

新版本的react里对contextapi调整过后,开发者能够更加直观地理解context的使用方式。

四. 参考

https://juejin.im/post/5a90e0545188257a63112977
https://www.jianshu.com/p/c7c47ead84c7
https://react.docschina.org/docs/context.html
https://yepbug.com/2018/11/11/react-context-and-simple-redux/
http://huziketang.mangojuice.top/books/react/lesson29

猜你喜欢

转载自blog.csdn.net/colinandroid/article/details/88175750