在React
中很容易根据组件从而跟踪数据流,当你使用一个组件时,可以通过看props
来判断用了哪一些东西。
有时候你想直接通过组件树来讲数据传递子元素,而不是通过props
一层一层的传递下去,可以使用Reac
t提供的contextAPI
来处理。
1.为什么一般都不使用Context
虽然React
提供了context
来处理以上事件 ,但是一般情况下是不需要使用这个API
的。
如果你想要你的应用尽可能的稳定的话,请不要使用Context
,因为这在React
属于一种实验性质的API
,在未来的React
版本中可能被抛弃。
如果你不是一个非常有经验的开发人员,也请不要使用context
,通常都有更好方法来实现我们的要求
如果你硬是要用Context
,请在小范围中使用
2.使用context
的方法
class Button extends React.Component {
render() {
return (
<button style={{background: this.props.color}}>
{this.props.children}
</button>
);
}
}
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button color={this.props.color}>Delete</Button>
</div>
);
}
}
class MessageList extends React.Component {
render() {
const color = "purple";
const children = this.props.messages.map((message) =>
<Message text={message.text} color={color} key={index} />
);
return <div>{children}</div>;
}
}
上面的我们给button
设置颜色,竟然要从顶层的组件一步一步的通过props
传递下去,很烦。
如果是使用context
就会非常简单了
class Button extends React.Component {
render() {
return (
<button style={{background: this.context.color}}>
{this.props.children}
</button>
);
}
}
//重点
Button.contextTypes = {
color: React.PropTypes.string
};
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button>Delete</Button>
</div>
);
}
}
class MessageList extends React.Component {
//重点
getChildContext() {
return {color: "purple"};
}
render() {
const children = this.props.messages.map((message, index) =>
<Message text={message.text} key={index}/>
);
return <div>{children}</div>;
}
}
//重点
MessageList.childContextTypes = {
color: React.PropTypes.string
};
通过childContextTypes
和getChildContext
给MessageList
增加context
上下文,React
会自动将它传递给子组件,如果子组件设置了contextTypes
就会获取到这个上下文。如果子组件的contextTypes
没有设置的话,context
就会是一个空的。
3.父子耦合
context
可以让父组件和子组件建立一个直接数据交流的通道,React Router V4
就实现了这个功能,这里不详讲。
4.在生命周期函数中使用context
需要将context
通过参数传递
constructor(props, context)
componentWillReceiveProps(nextProps, nextContext)
shouldComponentUpdate(nextProps, nextState, nextContext)
componentWillUpdate(nextProps, nextState, nextContext)
componentDidUpdate(prevProps, prevState, prevContext)
上面这些函数以后会讲解
5.无状态函数式组件中的context
这里先声明一下函数式组件本身无法使用this.state来进行状态标记控制
const Button = ({children}, context) =>
<button style={{background: context.color}}>
{children}
</button>;
Button.contextTypes = {color: React.PropTypes.string};
当我们将context
当做参数传入函数式组件,并且contextTypes
进行了类型检测控制,就可以在函数式组件内部使用context
6.更新Context
虽然React
有更新Context
的函数,但是对不起,依旧不希望你去使用context
,这算是警告中的警告了。
在前面写的时候,我就已经使用getChildContext
来处理数据,这个函数会在state
和props
改变时被调用。只要对state
和props
进行更新就可以实现context
的更新。
class MediaQuery extends React.Component {
constructor(props) {
super(props);
this.state = {type:'desktop'};
}
getChildContext() {
return {type: this.state.type};
}
componentDidMount() {
const checkMediaQuery = () => {
const type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';//这个是用来识别是PC端还是移动端(IE10+)
if (type !== this.state.type) {
this.setState({type});
}
};
window.addEventListener('resize', checkMediaQuery);
checkMediaQuery();
}
render() {
return this.props.children;
}
}
MediaQuery.childContextTypes = {
type: React.PropTypes.string
};
当然使用这个更新也会出问题,就是我们的shouldComponentUpdate
函数返回false
的时候,会导致子组件不更新状态,从而让子组件的context
超出控制。
下一篇将讲
React
中的WEB
组件