原生React组件之间的数据传输主要依赖于两个关键词:属性(props) 和状态(state)。每一个组件都是一个对象,props是对象的一个属性,组件对象可以通过props进行传递。React 的核心思想是组件化的思想,应用由组件搭建而成,而组件中最重要的概念是State(状态),State是一个组件的UI数据模型,是组件渲染时的数据依据。state与props的最大区别在于props是不可变的而state是可变的。具体内容后面会详细讲解。
原生React组件之间数据传递场景可以分为以下四种:
- 组件内部的数据传输
- “父组件”向“子组件”传值
- “子组件”向 “父组件”传值
- “兄弟组件”之间的传值
1、组件内部的数据传输
在初学过程的项目开发中常常会有去尝试DOM操作的冲动,虽然大部分情况下这种尝试是错误的,但是在某些时候还是不得不需要获取对DOM的值进行操作。例如:点击一个按钮之后触发一个点击事件,让一个input文本框获得焦点。jQuery开发者的第一反应肯定是给button绑定点击事件,然后在事件中通过$(‘select’)获取到要操作的节点,再给节点添加焦点。然而在React中这种操作是不允许的,而React中应该怎么做呢?
React Refs属性:
import React, { Component } from 'react';
class MyComponent extends Component({
handleClick = () => {
// 使用原生的 DOM API 获取焦点
this.refs.myInput.focus();
},
render: function() {
// 当组件插入到 DOM 后,ref 属性添加一个组件的引用于到 this.refs
return (
<div>
<input type="text" ref="myInput" />
<input
type="button"
value="点我输入框获取焦点"
onClick={this.handleClick}
/>
</div>
);
}
});
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
);
我们可以从上面的代码当中看到 其中的ref在功能上扮演起了一个标识符(id)的角色,this.refs.myInput.focus()也有一种document.getElementById(‘myInput’).focus()的味道。
上面的操作我们也称为React表单事件,React表单事件中除了ref具有关键作用外,还有另一个关键参数’event’。例如:当我需要实时获取到一个文本框里面的内容,然后进行一个判断,当满足某个条件的时候触发另一个事件。这个时候就需要使用到这个一个关键参数’event’。
React 表单事件-event参数:
class MyComponent extends Component{
handleChange = (event) => {
if(event.target.value === 'show'){
console.log(this.refs.showText);
}
};
render(){
return(
<div>
<input type="text" onChange={this.handleChange}/>
<p ref='showText'>条件满足我就会显示在控制台</p>
</div>
)
}
}
export default MyComponent;
上面实例实现的效果就是,通过event.target.value获取当前input中的内容,当input中输入的内容是show的时候,控制台就将ref为showText的整个节点内容打印出来。从这个实例当中我们也看到了,event作为一个默认参数将对应的节点内容进行了读取。
因此在组件内部涉及的DOM操作数据传递主要就是这两种方式,可以根据不同的场景选择不同的方式。虽然ref适用于所有组件元素,但是ref在正常的情况下都不推荐使用,后面会进行介绍通过 state管理组件状态,避免进行DOM的直接操作。
2、“父组件”向“子组件”传值
父组件与子组件之间的通信通常使用props进行。具体如下:
import React,{ Component } from 'react'
class ChildComponent extends Component{
render (){
return (
<div>
<h1>{this.props.title}</h1>
<span>{this.props.content}</span>
</div>
)
}
}
class ParentComponent extends Component {
render (){
return (
<div>
<ChildComponent title="父组件与子组件的数据传输测试" content="我是传送给子组件span中显示的数据" />
<p>我是父组件的内容</p>
</div>
)
}
}
export default ParentComponent;
上面示例展示了父组件向子组件传递了两个props属性分别为title和content,子组件通过this.props获取到对应的两个属性,并将其展示出来,这个过程就是一个父与子组件之间的数据交互方式。但是也可以从例子中看到props的值是不变的,父传给子什么样的props内容就只能接收什么样的使用,不能够在子中进行重新赋值。
3、“子组件”向 “父组件”传值
本例中将会引入了管理组件状态的state,并进行初始化。具体如下:
import React, { Component } from 'react';
//子组件
class Child extends Component {
render(){
return (
<div>
请输入邮箱:<input onChange={this.props.handleEmail}/>
</div>
)
}
}
//父组件,此处通过event.target.value获取子组件的值
class Parent extends Component{
constructor(props){
super(props);
this.state = {
email:''
}
}
handleEmail = (event) => {
this.setState({email: event.target.value});
};
render(){
return (
<div>
<div>用户邮箱:{this.state.email}</div>
<Child name="email" handleEmail={this.handleEmail}/>
</div>
)
}
}
export default Parent;
通过上面的例子可以看出”子组件”传递给”父组件”数据其实也很简单,概括起来就是:react中state改变了,组件才会update。父写好state和处理该state的函数,同时将函数名通过props属性值的形式传入子,子调用父的函数,同时引起state变化。子组件要写在父组件之前。
从本示例中也可以看出state可以通过setState进行重新赋值,因此state是可变的,表示的是某一时间点的组件状态。
4、“兄弟组件”之间的传值
当两个组件不是父子关系,但有相同的父组件时,将这两个组件称为兄弟组件。严格来说实际上React是不能进行兄弟间的数据直接绑定的,因为React的数据绑定是单向的,所以才能使得React的状态处于一个可控的范围。对于特殊的应用场景中,可以将数据挂载在父组件中,由两个组件共享:如果组件需要数据渲染,则由父组件通过props传递给该组件;如果组件需要改变数据,则父组件传递一个改变数据的回调函数给该组件,并在对应事件中调用。从而实现兄弟组件之间的数据传递。
import React, { Component } from 'react';
//子组件
class Child extends Component {
render(){
return (
<div>
我是子组件邮箱:<input onChange={this.props.handleEmail} defaultValue={this.props.value} />
</div>
)
}
}
//兄弟组件
class ChildBrother extends Component {
render(){
return (
<div>
我是兄弟组件:{this.props.value}
</div>
)
}
}
//父组件,此处通过event.target.value获取子组件的值
class Parent extends Component{
constructor(props){
super(props);
this.state = {
email:''
}
}
handleEmail = (event) => {
this.setState({email: event.target.value});
};
render(){
return (
<div>
<div>我是父组件邮箱:{this.state.email}</div>
<Child handleEmail={this.handleEmail} value={this.state.email}/>
<ChildBrother value={this.state.email}/>
</div>
)
}
}
export default Parent;
上面例子中就是child组件的值改变后存储在父组件的state中,然后再通过props传递给兄弟组件childBrother。从而实现兄弟组件之间的数据传递。