App.jsx:
import { useEffect, useState } from 'react'
import ChildActions from './components/ChildActions.jsx'
import './App.css'
export default function App() {
const [count, setCount] = useState(0)
const [fromChild, setFromChild] = useState('(还没有)')
const handleStep = (delta) => {
setCount((c) => c + delta)
}
const handleSend = (text) => {
setFromChild(text.trim() === '' ? '(空字符串)' : text)
}
useEffect(() => {
document.title = '子传父 · 回调'
}, [])
return (
<main className="app">
<h1>子组件 → 父组件(回调 props)</h1>
<p className="hint">
数据存在<strong>父组件</strong>的 <code>useState</code> 里。父组件把{' '}
<code>handleStep</code>、<code>handleSend</code> 通过 props 交给子组件;子组件在点击时调用它们,相当于把孩子里的信息交给了父组件。
</p>
<p className="count">
父 state · 计数:<strong>{count}</strong>
</p>
<p className="count">
父 state · 子传来的话:<strong>{fromChild}</strong>
</p>
<ChildActions onStep={handleStep} onSend={handleSend} />
</main>
)
}
ChildActions.jsx:
import { useState } from 'react'
export default function ChildActions({ onStep, onSend }) {
const [draft, setDraft] = useState('')
return (
<div className="child">
<p className="child__label">子组件:通过调用父传入的函数,把数据「传上去」</p>
<div className="actions">
<button type="button" onClick={() => onStep(5)}>
子:+5
</button>
<button type="button" onClick={() => onStep(-2)}>
子:−2
</button>
</div>
<div className="child__row">
<input
className="child__input"
type="text"
placeholder="输入一句话"
value={draft}
onChange={(e) => setDraft(e.target.value)}
/>
<button
type="button"
onClick={() => {
onSend(draft)
setDraft('')
}}
>
子:把输入传给父
</button>
</div>
</div>
)
}
App.css:
.app {
max-width: 30rem;
margin: 2.5rem auto;
padding: 0 1.25rem;
font-family: system-ui, sans-serif;
line-height: 1.55;
color: #1a1a1a;
}
.app > h1 {
font-size: 1.25rem;
font-weight: 650;
margin: 0 0 0.65rem;
}
.hint {
margin: 0 0 1.1rem;
font-size: 0.9rem;
color: #555;
}
.hint code {
font-size: 0.85em;
background: #f3f4f6;
padding: 0.08em 0.35em;
border-radius: 4px;
}
.count {
margin: 0 0 0.5rem;
font-size: 0.98rem;
}
.count:last-of-type {
margin-bottom: 1.15rem;
}
.child {
border: 1px solid #e5e7eb;
border-radius: 10px;
padding: 1rem 1.1rem;
background: #fafafa;
}
.child__label {
margin: 0 0 0.85rem;
font-size: 0.88rem;
color: #444;
}
.child__row {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 0.85rem;
align-items: center;
}
.child__input {
flex: 1;
min-width: 10rem;
padding: 0.4rem 0.55rem;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 0.95rem;
box-sizing: border-box;
}
.actions {
display: flex;
flex-wrap: wrap;
gap: 0.6rem;
}
.actions button,
.child__row button {
padding: 0.45rem 0.9rem;
font-size: 0.92rem;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 6px;
background: #fff;
}
.actions button:hover,
.child__row button:hover {
background: #f9fafb;
}

相关知识点总结:
通信方向:子组件 → 父组件,通过回调函数实现
实现原理:父组件定义事件处理函数,通过 props 传递给子组件;子组件触发时调用该函数
数据传递:子调用函数时可传入参数,将数据 / 消息传给父组件
状态管理:数据 / 状态始终保存在父组件,子组件只负责触发更新
核心语法:父传 onXxx 回调 props,子通过 props.onXxx(参数) 调用
作用:实现子组件通知父组件、子向父传值、子触发父状态更新