React中数据流是自上而下单向流动的,即父组件->子组件->子组件的子组件…,可以通过组件的props属性一级一级地传递和接收。
下面的示例中,MessageList 为父组件,Message 为子组件,Button 为子组件的子组件,通过props一级一级地传递和接收属性:
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} />
);
return <div>{children}</div>;
}
}
我们注意到,在子组件Message 中并没用用到父组件MessageList 传递过来的color属性,而是立即将该属性传给他的Button 子组件,那么,我们是否可以不通过中间的组件Message ,而直接从父组件MessageList 将属性传递给组件Button 呢?
context
全局空间:父组件设置context并放入某状态,其下每个孩子组件都可以从其取得状态,而不用一层一层的向下传递。
注意:父组件的父组件是无法访问到context中存放的状态的。
语法:
static childContextTypes = {
<key>: PropTypes.<类型>
}
getChildContext () {
return {
<key>: <value>
}
}
childContextTypes:是为context中的字段设置类型检查,必须设置
getChildContext():用来设置组件的context
子组件要使用:
//contextTypes首先要类型检查,必须的
class Title extends Component {
static contextTypes = {
themeColor: PropTypes.string
}
//this.context.<key>即可获取
render () {
return (
<h1 style={{ color: this.context.themeColor }}>React</h1>
)
}
示例:
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) =>
<Message text={message.text} />
);
return <div>{children}</div>;
}
}
MessageList.childContextTypes = {
color: React.PropTypes.string
};
分析:
- 在父组件MessageList中,通过childContextTypes定义了该组件的context对象:只有一个属性color,且必须是字符串
- 然后通过getChildText方法对context对象的属性赋值:color的值为purple
- 父组件的context对象完成
- 在第二级子组件Button中通过contextTypes申明接受到的context对象:只有一个属性color,且必须是字符串
- 然后通过this.context.color使用context对象中的属性
这样就实现了跨级传递属性。
这种方式有一个很大的缺点就是子组件可以随意得修改context对象的属性值,因为context类似一个全局变量,当组件层级多的时候就很容易出现混乱,因此不推荐使用这种方式传递属性。