React 第九节 组件之间通讯之props 和回调函数
1、父组件向子组件通过 props 进行通讯
首先请先了解组件的三大属性之 props
补充以下内容,基于函数式组件
1.1、单个属性传递
// 父组件
import { useState } from 'react'
// 引入 ChildA 组件
import ChildA from './childA'
export default function MyComP() {
const [name, setName] = useState('Andy')
const [age, setAge] = useState(18)
const [students, setStudents] = useState([])
return (
<>
<h2>父组件</h2>
{/* 单个属性传递 */}
<ChildA name={name} age={age}></ChildA>
</>
)
}
// 子组件
export default function ChildA(props) {
console.log('==data==', props)
// 若子组件需要对传入的 props 数据进行再次加工,类似 VUE 中写法,需要使用新的变量接住 props的属性,比如自身名称 需要在父组件名称基础上 +1,如:
const [selfName, setSelfName] = useState(props.name)
const handleChangeSelfName = () => {
setSelfName(`${selfName}+1`)
}
return (
<>
<h3>childA组件:</h3>
{/* 子组件中如果不需要 对props 传递进来的值进行二次加工,则直接展示使用即可 */}
<p>操作人员:{props?.name ?? '--'}</p>
<p>年龄:{props?.age ?? '--'}</p>
<p>子组件自身名称:{setSelfName}</p>
<button onClick={handleChangeSelfName}>修改自身名称</button>
</>
)
}
1.2、多个属性 对象、数组 进行传递
// 父组件
import { useState } from 'react'
import ChildA from './childA'
export default function MyComP() {
const [students, setStudents] = useState([
{name: '张三', age:18},
{name: '李四', age: 19},
{name: '王五', age: 20},
])
const [useInfo, setUseInfo] = useState({
name: 'Andy',
age: 18,
gender: '男',
address: '郑州',
})
return (
<>
<h2>父组件</h2>
{/* 通过扩展运算符,或者将整个数组对象传给子组件 */}
<ChildA students={students} useInfo={{...useInfo}}></ChildA>
</>
)
}
// 子组件
import {useState} from 'react'
export default function ChildA(props) {
console.log('==data==', props)
return (
<>
<h3>学生信息:</h3>
<ul>
{
props.students.map((student, index) =>{
return(
<li key={index}>
<p>姓名:{student.name}</p>
<p>年龄:{student.age}</p>
</li>
)
})
}
</ul>
</>
)
}
1.3、函数式组件中 默认值的写法
通过 defaultProps 设置默认值
这种方式赋默认值,在函数式组件,类式组件中都适用
import React from 'react'
export default function ChildB(props) {
return (
<>
<h2>子组件B</h2>
<p>年龄:{props?.age ?? '--'}</p>
<p>子组件操作人员:{props?.name ?? '--'}</p>
</>
)
}
ChildB.defaultProps = {
name: 'ChildB', // 设置默认名称与年龄
age: 20,
}
在函数式组件中直接给参数添加默认值
这种形式 只适合 函数式组件,并且对于多个参数需要赋默认值的行为,不太友好;
import React from 'react'
export default function ChildB({name='ChildB', age=23}) {
return (
<>
<h2>子组件B</h2>
<p>年龄:{age ?? '--'}</p>
<p>子组件操作人员:{name ?? '--'}</p>
</>
)
}
1.4、父组件 通过children 属性 向子组件传 对象 dom结构
知道有这么回事就行,不建议使用,削减了组件的健壮性,
类似vue中插槽
的作用
```javascript
// 父组件
import { useState, useRef, useEffect } from 'react'
import ChildB from './childB'
export default function MyComP() {
const [name, setName] = useState('Andy')
const [useInfo, setUseInfo] = useState({
name: 'Andy',
age: 18,
gender: '男',
address: '郑州',
})
const handleChangNaem = (newName) => {
setName(newName)
}
const handleChangeRef = () => {
console.log('---myComRef-',)
}
return (
<>
<h2>父组件</h2>
<ChildB onChangName={handleChangNaem} name={name} >
{/* 可以传递多种类型,多个节点 */}
{/* 向子组件传递额外属性 */}
{{...useInfo}}
{/* 向子组件传递 dom结构 */}
<span>children 数据</span>
</ChildB>
</>
)
}
```
子组件接收 props 的children属性,children是一个数组
```javascript
export default function ChildB({name, onChangName, children}) {
console.log('===children=', children)
const [text, setText] = useState('')
const handleChangNaem = () => {
console.log('修改名称')
onChangName('Andy222') // 假设修改名称
}
return (
<div>
<h2>子组件B</h2>
<p>子组件操作人员:{name ?? '--'}</p>
<button onClick={handleChangNaem}>修改名称</button>
<p>用户信息{children[0].name}</p>
<p>{children[1]}</p>
</div>
)
}
```
children 是一个数组,可以通过数组的 map、forEach 方法进行遍历;
父组件传递的数据可以是 基本类型变量、引用类型变量、DOM结构、还可以是函数
注意:空节点(null,undefined 以及布尔值),字符串
,数字
和 React 元素 都会被统计为单个节点。在遍历统计的过程中,React 元素不会被渲染,所以其子节点不会被统计。Fragment 也不会被统计
2、子组件通过回调函数向父组件传值
// 父组件
import { useState } from 'react'
import ChildB from './childB'
export default function MyComP() {
const [name, setName] = useState('Andy')
const [age, setAge] = useState('18')
const handleChangNaem = (newName) => {
setName(newName)
}
return (
<>
<h2>父组件</h2>
{/* 父组件 通过 onChangName 函数接收 子组件传递参数 */}
<ChildB onChangName={handleChangNaem} name={name}></ChildB>
</>
)
}
// 子组件 通过onChangeName 给父组件传递新名称
export default function ChildB({name='ChildB', age=23, onChangName}) {
const handleChangNaem = () => {
console.log('修改名称')
onChangName('Andy222') // 假设修改名称
}
return (
<>
<h2>子组件B</h2>
<p>年龄:{age ?? '--'}</p>
<p>子组件操作人员:{name ?? '--'}</p>
<button onClick={handleChangNaem}>修改名称</button>
</>
)
}