React学习笔记(7) - 父子通信

  • React中,父子组件间的通信是非常常见的问题,除了使用状态管理工具(如redux)以外,也可以实现父子组件的相互通信。其中,父组件可以通过props原型方法向子组件通信,子组件可以通过回调函数事件冒泡向父组件通信。

1. 父组件向子组件通信

  • 父组件项子组件通信中最常见的办法就是通过props(属性),代码如下:
import React, { Component } from 'react'
import myPropTypes from 'prop-types'// 引入属性验证库(propTypes,引入名字可以随便取)

// 组件间通信: 父传子使用属性(props)

// 子组件
class Son extends Component {

/*
1.属性验证(static:表示静态属性,意味着这个类不需要实例化也能读取到里面的属性)
这种方法推荐使用
*/
static propTypes = {
money:myPropTypes.number,//并且可以设置属性验证来限制接收数据的类型
}
render() {
// 通过this.props来接受父组件穿过来的数据
console.log('接收到父组件传过来的数据',this.props);
return (
<div>
儿子组件-{this.props.money}
</div>
)
}
}

// 父组件
export default class Father extends Component {
render() {
return (
<div>
{/* 父组件将money=500属性传给子组件 */}
<Son money={500}/>
</div>
)
}
}

结果展示:

image

  • 第二种,使用原型方法,父组件通过React.createRef()创建Ref,保存在实例属性对应生成的ref上。父组件中,渲染子组件时,定义一个Ref属性,值为刚创建的对应的ref,并且在子组件设计的时候自带一个方法用于传值,随后在父组件中调用子组件的时候,父组件通过ref属性来获取到子组件中用于传值的方法。
import React, { Component } from 'react'

// 组件间通信: 父传子使用原型方法

// 子组件
class Son extends Component {
state={
money : ''
}
// 子组件在设计的时候内置一个方法用于传值
getData(data){
console.log('成功接收到父组件传过来的数据',data);
this.setState({ // 将接受过来的父组件数据作状态保存
money:data.money
})
}
render() {
return (
<div>
{/* 输出父组件接收过来的数据 */}
儿子组件-{this.state.money}
</div>
)
}
}

// 父组件
export default class Father extends Component {
// 创建Ref,并保存在实例属性myRef上
myRef = React.createRef();

render() {
return (
<div>
{/* 父组件将money=500属性传给子组件 */}
<Son ref={this.myRef}/>
</div>
)
}

// 组件挂载生命周期
componentDidMount() {//调用生命周期函数在页面挂载的时候调用子组件中的方法将数据传给子组件
// 调用子组件的函数,传递一个参数
this.myRef.current.getData({money:500});
}
}

结果展示:

image

2. 子组件向父组件通信

  • 子组件向父组件传数据方法之一:回调函数,使用起来与props属性也是非常相似的,我们在父组件中引入了子组件,同样给子组件传一个属性过去,但是相较于props的传数据,子传父方法传的是回调函数(callback),首先在父组件中给子组件通过props的形式绑定一个回调函数,这个回调函数里面可以写上子组件传数据过来给父组件的逻辑,随后在子组件中通过this.props.callback的形式接收到父组件传过来的方法,我们在调用这个方法发挥数据给父组件即可
import React, { Component } from 'react'

// 组件间通信: 子传父使用回调函数方法(类似props)

// 子组件
class Son extends Component {
render() {
return (
<div>
{/* 通过props接收到父组件传过来的方法,作数据返回 */}
<button onClick={() => {this.props.event({money:500});}}>点击给父组件发送数据</button>
</div>
)
}
}

// 父组件
export default class Father extends Component {

render() {
return (
<div>
{/* 父组件设置一个接收数据的方法通过props的形式绑定到子组件上 */}
<Son event={(data)=>{
// 输出子组件穿过来的数据
console.log('成功从子组件中接收到数据',data);
}}/>
</div>
)
}
}

结果展示:

image

登陆页面的案例(结合父子通信以及表单富文本的使用)

  • 将输入的账号密码设置为一个组件,随后在登陆页面上引用这个组件,通过ref实现子传父,通过props实现父传子

代码展示:

import React, { Component } from 'react'

// 子组件
class Field extends Component{
state = {
value:""
}

clear(){//清空输入框
this.setState({
value:""
})
}

setValue(value){//接收父组件传过来的数据并同步到输入框
this.setState({
value:value
})
}

render(){
return <div style={{background:"yellowgreen"}}>
{/* 展示父组件传过来的数据 */}
<label>{this.props.label}</label>
<input type={this.props.type} onChange={(evt)=>{
this.setState({
value:evt.target.value
})
}} value={this.state.value}/>
</div>
}
}

export default class App extends Component {
username = React.createRef()//设置用户名的ref
password = React.createRef()//设置密码的ref

render() {
return (
<div>
<h1>登录页面</h1>
{/* 通过props传值将数据传过去给子组件同时设置ref属性用于获取对应的组件实例 */}
<Field label="用户名" type="text" ref={this.username}/>
<Field label="密码" type="password" ref={this.password}/>

<button onClick={()=>{
// 点击登录过后通过ref属性输出当前输入框中的数据(账号,密码)
console.log('账号:',this.username.current.state.value,
'密码',this.password.current.state.value
)
}}>登录</button>
<button onClick={()=>{
// 点击取消过后,通过ref指向并调用对应的组件中的清空数据的方法
this.username.current.clear()
this.password.current.clear()
}}>取消</button>
</div>
)
}
}

结果展示:

image