react组件的数据分为两种,prop(代表property)和state。
1、父子组件间的数据传递主要使用prop。
2、子组件接收的prop的数据格式是由prop-types进行检测的,当不符合时,会在console控制台提出警告(可用于开发环境)。
prop的类型:不同的类型实现了父子组件间不同方向的数据传递
一、普通数据类型:可用于外部世界向子组件内部传递数据。
注意:这里是使用了create-react-app快速搭建了react结构。
(1)入口js文件:
其中ControlPanel是自定义组件。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import ControlPanel from './ControlPanel';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<ControlPanel />, document.getElementById('root'));
registerServiceWorker();
(2)ControlPanel自定义父组件的定义,其中Counter是子组件。
import React ,{Component} from 'react';
import Counter from './Counter';
export default class ControlPanel extends Component{
render(){
return (
<div>
{/*使用多个子组件,并且通过两个prop向子组件Counter进行数据传递:caption和initValue。*/}
<Counter caption="First" initValue={0}></Counter>
<Counter caption="Second" initValue={10}></Counter>
<Counter caption="Third" initValue={20}></Counter>
</div>
)
}
}
(3)Counter子组件内容:
注意:
当当前组件需要使用父组件通过prop传递过来的数据时,必须在构造函数的第一行调用父类(React.Component)构造函数,即super(props)
。即this.props的赋值是React.Compnent构造函数的工作之一。
import React,{Component} from 'react';
// 注意:react最新版本已经将proptypes独立出来,需要自行安装prop-types才可以使用。
import PropTypes from 'prop-types';
//直接在定义组件的时候,将组件导出。
export default class Counter extends Component{
constructor(props){
super(props);
this.onJia=this.onJia.bind(this);
this.onJian=this.onJian.bind(this);
this.state={
// 使用父组件传递过来的初始值,这里可以用短路操作,也可以使用下面提到的defaultProps来进行设置
counter:props.initValue||0
}
}
onJia(){
this.setState({
counter:this.state.counter+1
})
}
onJian(){
this.setState({
counter:this.state.counter-1
})
}
render(){
const btnStyle={
margin:"0 20px"
};
return (
<div>
{/*获取到父组件传递的文字内容*/}
{this.props.caption}:
<button onClick={this.onJia} style={btnStyle}>+</button>
<span>{this.state.counter}</span>
<button onClick={this.onJian} style={btnStyle}>-</button>
</div>
)
}
}
// 这个propTypes只能在开发阶段辅助检测父向子传递数据的类型及是否必备。
// 在生产环境中,无意义,可使用 babel-react-optimize 去掉propTypes验证。
Counter.propTypes={
caption:PropTypes.string.isRequired,
initValue:PropTypes.number
}
// defaultProps 用于设置默认值,当父向子组件未传递时的默认值。
Counter.defaultProps={
initValue:0
}
二、函数数据类型:相当于父组件向子组件传递了一个函数,在子组件内部某一个时刻执行这个函数,就会将子组件的数据传递给父组件中。
(1)步骤一:在父组件中定义函数,约定参数。
(2)步骤二:给指定的子组件设置传递的属性
(3)步骤三:在子组件中,确定父组件传递过来的函数 *执行 *的位置,及传入的参数。
- 应用实例:子组件做任意修改,父组件均正常显示总和。
在父组件中实时显示多个子组件的总和。
修改ControlPanel文件内容如下:
import React ,{Component} from 'react';
import Counter from './Counter';
export default class ControlPanel extends Component{
constructor(props){
super(props);
this.onCounterUpdate=this.onCounterUpdate.bind(this);
// 每一个ContrlPanel组件类的私有属性
this.initValues=[0,10,20];
// 获得初始加和的值,reduce函数获取到加和结果,如果没有默认为0。
const initSum=this.initValues.reduce((a,b)=>a+b,0);
this.state={
sum:initSum
}
}
// 步骤一:在父组件中定义函数,约定参数。
// 在父组件中定义函数,约定参数一是更新后的值,参数二是原值。
onCounterUpdate(newValue,previousValue){
const valueChange=newValue-previousValue;
// 触发state值的改变,引发重新渲染。
this.setState({
sum:this.state.sum+valueChange
})
}
render(){
return (
<div>
{/*步骤二:给指定的子组件设置传递的属性*/}
{/*通过给子组件设置属性的方式传递定义的函数onCounterUpdate*/}
<Counter caption="First" initValue={this.initValues[0]} onUpdate={this.onCounterUpdate}></Counter>
<Counter caption="Second" initValue={this.initValues[1]} onUpdate={this.onCounterUpdate}></Counter>
<Counter caption="Third" initValue={this.initValues[2]} onUpdate={this.onCounterUpdate}></Counter>
<hr/>
{/*展示总和*/}
<div>Total Count:{this.state.sum}</div>
</div>
)
}
}
修改Counter文件内容如下:
import React,{Component} from 'react';
// 注意:react最新版本已经将proptypes独立出来,需要自行安装prop-types才可以使用。
import PropTypes from 'prop-types';
export default class Counter extends Component{
constructor(props){
super(props);
this.onJia=this.onJia.bind(this);
this.onJian=this.onJian.bind(this);
this.state={
// 使用父组件传递过来的初始值
counter:props.initValue||0
}
}
onJia(){
this.updateCount(true);
}
onJian(){
this.updateCount(false);
}
// 增加、减少共用此函数
updateCount(isIncrement){
const previousValue=this.state.counter;
const newValue=isIncrement?previousValue+1:previousValue-1;
this.setState({counter:newValue});
// 步骤三:在子组件中,确定父组件传递过来的函数执行的位置,及传入的参数。(此案例中,需要在每一次加减按钮操作时,均实时显示出总和,所以写在了公共函数的内部)
// 在子组件中调用传递过来的函数,实参一是新值,实参二是老值。
// 一旦调用,就会触发state的更新,从而引发重新渲染。
this.props.onUpdate(newValue,previousValue);
}
render(){
const btnStyle={
margin:"0 20px"
};
return (
<div>
{this.props.caption}:
<button onClick={this.onJia} style={btnStyle}>+</button>
<span>{this.state.counter}</span>
<button onClick={this.onJian} style={btnStyle}>-</button>
</div>
)
}
}
Counter.propTypes={
caption:PropTypes.string.isRequired,
initValue:PropTypes.number,
onUpdate:PropTypes.func
};
Counter.defaultProps={
initValue:0,
onUpdate:f=>f
};