React中的Context怎么用

前端之家收集整理的这篇文章主要介绍了React中的Context怎么用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

What is Context

今天在学习styled-componentsTheming时,关于styled-components主题的实现与管理上提到,主要应用到了reactcontext API,所以好好研读了一下官方文档,对该API做了如下记录。

什么是Context

当我们使用React时,很容易的通过观察组件的props来跟踪组件间的数据流流向,这种跟踪观察方式也让我们很容易的去理解组件。

而有的时候,我们不想让一个props从最外层,通过组件一层一层的传递到目标组件上,这时就可以通过context来直接实现我们希望的操作。

怎样使用Context

假设有个如下的结构:

  1. class Button extends React.Component {
  2. render() {
  3. return (
  4. <button style={{background: this.props.color}}>
  5. {this.props.children}
  6. </button>
  7. );
  8. }
  9. }
  10.  
  11. class Message extends React.Component {
  12. render() {
  13. return (
  14. <div>
  15. {this.props.text} <Button color={this.props.color}>Delete</Button>
  16. </div>
  17. );
  18. }
  19. }
  20.  
  21. class MessageList extends React.Component {
  22. render() {
  23. const color = "purple";
  24. const children = this.props.messages.map((message) =>
  25. <Message text={message.text} color={color} />
  26. );
  27. return <div>{children}</div>;
  28. }
  29. }

上面的例子中,我们把color手动的方式传给了Button,这期间穿越了Message,而对Message本身没有什么用。如果用context的话,可以直接给到Button组件上,如下:

  1. const PropTypes = require('prop-types');
  2.  
  3. class Button extends React.Component {
  4. render() {
  5. return (
  6. <button style={{background: this.context.color}}>
  7. {this.props.children}
  8. </button>
  9. );
  10. }
  11. }
  12.  
  13. Button.contextTypes = {
  14. color: PropTypes.string
  15. };
  16.  
  17. class Message extends React.Component {
  18. render() {
  19. return (
  20. <div>
  21. {this.props.text} <Button>Delete</Button>
  22. </div>
  23. );
  24. }
  25. }
  26.  
  27. class MessageList extends React.Component {
  28. getChildContext() {
  29. return {color: "purple"};
  30. }
  31.  
  32. render() {
  33. const children = this.props.messages.map((message) =>
  34. <Message text={message.text} />
  35. );
  36. return <div>{children}</div>;
  37. }
  38. }
  39.  
  40. MessageList.childContextTypes = {
  41. color: PropTypes.string
  42. };

通过给MessageList(Context宿主)添加childContextTypesgetChildContext,可以实现在该组件子结构下的所有组件(e.g. Button)直接通过定义contextTypes获取

如果未定义contextTypes的话,context是一个空对象。

获取Context对象的勾子函数

一旦组件定义了contextTypes以后,以下的勾子中就会得到一个附加的参数——context对象:

无状态组件获取Context方法

无状态组件同样可以通过给函数定义contextTypes属性的方式,让组件拥有获取context的能力,例如:

  1. const PropTypes = require('prop-types');
  2.  
  3. const Button = ({children},context) =>
  4. <button style={{background: context.color}}>
  5. {children}
  6. </button>;
  7.  
  8. Button.contextTypes = {color: PropTypes.string};

Context的更新

不要更新Context!

React虽然有提供关于更新context的API,但不建议去使用。

如果想用的话,可以看下面的这个例子。
getChildContext方法会在stateprops更新时被调用,可以通过局部状态的更新进而来更新context。当context更新后,所有的子组件都能接到新值。

  1. const PropTypes = require('prop-types');
  2.  
  3. class MediaQuery extends React.Component {
  4. constructor(props) {
  5. super(props);
  6. this.state = {type:'desktop'};
  7. }
  8.  
  9. getChildContext() {
  10. return {type: this.state.type};
  11. }
  12.  
  13. componentDidMount() {
  14. const checkMediaQuery = () => {
  15. const type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';
  16. if (type !== this.state.type) {
  17. this.setState({type});
  18. }
  19. };
  20.  
  21. window.addEventListener('resize',checkMediaQuery);
  22. checkMediaQuery();
  23. }
  24.  
  25. render() {
  26. return this.props.children;
  27. }
  28. }
  29.  
  30. MediaQuery.childContextTypes = {
  31. type: PropTypes.string
  32. };

这里有个问题是,如果宿主组件的context更新了,其下使用该context的子组件可能因为某个父组件的shouldComponentUpdate返回false而不做状态更新。这就完全不符合通过使用context来控制组件状态更新的初衷,所以证明使用context来管理组件状态不太靠谱。
这里有篇博客关于介绍如何安全的使用context的。

不建议使用Context

绝大多数的应用程序是不需要使用context的。

如果你想要你的应用稳定,就不要使用它,这是一个实验性的API,在未来的版本更新中很有可能会被弃掉。

context最好的使用场景是隐式的传入登录用户,当前的语言,或者主题信息。要不然所有这些可能就是全局变量,但是context让你限定他们到一个单独的React树里。

如果项目对数据管理较为复杂,推荐使用类似于reduxmobX这样的状态管理库,而不要使用context

记录的过程是一种成长,欢迎大家关注我的github

猜你在找的React相关文章