在前面的章节中,我们学习了 props 与 useState,并在上一章的最后一个案例中,为大家演示了父子组件通信的用法。在这一章,我们将进一步说明父子组件通信的注意事项。
父子组件通信是我们在使用 React 时的高频场景,他的表现主要有如下两个
一是子组件在父组件的声明中使用,父组件可以通过 props 将数据传递给子组件
1function Parent() {2return <Child name='张三' />3}
二是父组件通过 props 传入一个函数,子组件在自己的内部调用该函数,并将子组件内部的状态作为参数传递给该函数,从而实现子组件向父组件通信
10function Parent() {20const [name, setName] = useState('张三')30const handleClick = (name: string) => {40// 在回调函数中,获取从子组件传递过来的数据50setName(name)60}70return <Child name={name} handleClick={handleClick} />80}9010function Child({ name, handleClick }: { name: string; handleClick: (name: string) => void }) {11function __click() {12// 在回调函数中,将数据传递给父组件13handleClick('李四')14}15return <div onClick={__click}>子组件</div>16}
我们常常会基于 input
元素二次封装一个组件,如下所示。此时我们封装的 Input 组件,在 UI 上明确表示为输入用户名。
在设计上,我们为新的 Input 组件定义了两个 props,分别是 value
和 onChange
。以确保父组件可以向 Input 组件中传入值,并监听 Input 组件的值变化,从而实现父子组件通信。
1interface InputProps {2value: string,3onChange: (value: string) => void4}
完整的 Input 组件代码如下所示
10import {User} from 'lucide-react'2030interface InputProps {40value: string,50onChange: (value: string) => void60}7080export default function Input({ value, onChange }: InputProps) {90return (10<div className='flex py-2 px-4 items-center max-w-96 gap-2 border border-gray-300 rounded-xl dark:border-0 dark:inset-ring dark:inset-ring-white/10'>11<div className='flex flex-col flex-1'>12<div className='text-sm text-gray-500 pl-2'>用户名</div>13<input14type="text"15className='outline-none !border-0 m-0'16value={value}17onChange={e => onChange(e.target.value)}18placeholder='请输入用户名'19/>20</div>21<User size={20} />22</div>23)24}
在父组件中,我们可以则直接使用 Input 组件,并监听其值的变化即可。此时我们可以看到,在父组件的其他 UI 部分,就可以拿到在子组件中输入的值
10import { useState } from 'react'20import Input from './input'3040export default function Parent() {50const [value, setValue] = useState('')6070return (80<div>90<Input value={value} onChange={setValue} />10<div className='mt-4 text-sm'>11用户名为:{value}12</div>13</div>1415)16}
在后续的学习中,关于父子组件通信,我们还要学习受控组件与非受控组件的概念。这会在学习了 useEffect
后,为大家详细说明。