React父?jìng)髯拥膯雾?xiàng)數(shù)據(jù)流props的使用
前言
最近在學(xué)習(xí) React 的 props ,順手整理了自己的一些學(xué)習(xí)代碼和筆記。props 是 React 組件通信的核心,玩好了它,你寫組件就會(huì)像搭積木一樣順手。今天這篇文章,就從最基礎(chǔ)的用法開(kāi)始講起,一步步帶你深入,還會(huì)結(jié)合實(shí)際代碼例子來(lái)說(shuō)明。順便聊聊 React 19 前后的小變化、常見(jiàn)的 CSS 寫法,以及那個(gè)超級(jí)好用的 children props。
文章基于我自己的學(xué)習(xí)項(xiàng)目,代碼來(lái)自一個(gè)簡(jiǎn)單的 App,包含 Greeting、Card 和 Modal 組件。咱們邊看代碼邊聊,絕對(duì)干貨滿滿。
一、Props 是什么?為什么這么重要?(重點(diǎn)對(duì)比 state)
在 React 里,組件要正常工作,就離不開(kāi)“數(shù)據(jù)”。數(shù)據(jù)主要分兩類:state 和 props。這兩兄弟長(zhǎng)得有點(diǎn)像,但用途和性格完全不一樣,搞清楚它們的關(guān)系,你寫組件時(shí)才會(huì)心里有底。
用大白話總結(jié):
| 對(duì)比項(xiàng) | state(狀態(tài)) | props(屬性) |
|---|---|---|
| 是誰(shuí)的? | 組件自己的私有數(shù)據(jù) | 父組件傳給子組件的數(shù)據(jù) |
| 能不能改? | 可以改(用 setState 或 useState) | 只讀!子組件不能直接改 |
| 改了會(huì)怎樣? | 修改后組件會(huì)重新渲染 | 只有父組件重新傳新值,子組件才會(huì)更新 |
| 生命周期 | 屬于當(dāng)前組件,組件銷毀就沒(méi)了 | 像“快遞”一樣,從父組件送到子組件 |
| 典型用途 | 表單輸入值、開(kāi)關(guān)狀態(tài)、計(jì)數(shù)器等可變數(shù)據(jù) | 配置信息、顯示內(nèi)容、回調(diào)函數(shù)等 |
用生活例子比喻最清楚
想象你家有個(gè)兒子(子組件)和老爸(父組件):
- state 就像兒子自己的零花錢:他自己賺的(或爸給的初始值),想怎么花就怎么花(修改),爸管不著。
- props 就像爸給兒子的任務(wù)和工具:爸說(shuō)“今天幫我買瓶醬油,順便帶張電影票回來(lái)”,兒子只能按爸給的錢和要求去辦,不能自己改任務(wù)(“我偏要買可樂(lè)”不行)。
如果兒子想跟爸說(shuō)“我買完了”或者“我需要更多錢”,那只能通過(guò)爸事先給的“傳話方式”(回調(diào)函數(shù))來(lái)溝通——這就引出了我們上次講的“子傳父”。
代碼對(duì)比最直觀
來(lái)看同一個(gè)需求:顯示一個(gè)問(wèn)候語(yǔ),可以改名字和歡迎詞。
用 state 的方式(數(shù)據(jù)在組件自己手里):
import { useState } from 'react';
function GreetingSelf() {
const [name, setName] = useState('陌生人');
const [message, setMessage] = useState('歡迎光臨');
return (
<div>
<h1>Hello {name}</h1>
<p>{message}</p>
{/* 自己改自己,超級(jí)自由 */}
<input
placeholder="改名字"
onChange={(e) => setName(e.target.value)}
/>
<input
placeholder="改歡迎詞"
onChange={(e) => setMessage(e.target.value)}
/>
</div>
);
}
這個(gè)組件完全自給自足,想改啥改啥。
用 props 的方式(數(shù)據(jù)從外面?zhèn)鬟M(jìn)來(lái)):
function Greeting({ name, message }) {
return (
<div>
<h1>Hello {name}</h1>
<p>{message}</p>
{/* 這里不能改!想改得讓父組件來(lái) */}
{/* <input onChange=... /> // 沒(méi)用,props 是只讀的 */}
</div>
);
}
// 父組件
function App() {
const [name, setName] = useState('keji');
const [message, setMessage] = useState('歡迎來(lái)到騰訊');
return (
<div>
<Greeting name={name} message={message} />
{/* 只有這里能改,改了會(huì)重新傳給子組件 */}
<input value={name} onChange={(e) => setName(e.target.value)} />
<input value={message} onChange={(e) => setMessage(e.target.value)} />
</div>
);
}
看到區(qū)別了嗎?
- 用 state:組件內(nèi)部自己管數(shù)據(jù),適合獨(dú)立的小部件。
- 用 props:組件變成“純展示”工具,數(shù)據(jù)統(tǒng)一由父組件管理,適合復(fù)用(同一個(gè) Greeting 可以給不同人用不同歡迎詞)。
二、React 19 之前:Props 的經(jīng)典玩法
在 React 18 及更早版本,props 用法已經(jīng)很成熟了:
解構(gòu) props:直接在參數(shù)里解構(gòu),用起來(lái)最爽。
默認(rèn)值:兩種方式
- ES6 默認(rèn)參數(shù):message = "默認(rèn)值"
- defaultProps(靜態(tài)屬性,已被廢棄)
示例(舊方式):
Greeting.defaultProps = { message: "歡迎來(lái)到字節(jié)" };類型檢查:用 prop-types 包
import PropTypes from "prop-types"; Greeting.propTypes = { name: PropTypes.string.isRequired, message: PropTypes.string, };開(kāi)發(fā)模式下,如果傳錯(cuò)類型會(huì)警告,很實(shí)用。
傳任意數(shù)據(jù):字符串、數(shù)字、對(duì)象、函數(shù)、甚至 JSX 都可以。
三、React 19 之后:Props 的小變化(更簡(jiǎn)潔了)
React 19(2024 年 12 月穩(wěn)定發(fā)布)對(duì) props 本身的核心機(jī)制沒(méi)大改,但有一些清理和改進(jìn),讓代碼更現(xiàn)代:
移除 propTypes 和 defaultProps:這些早在 React 15.5 就被標(biāo)記廢棄了,React 19 直接從 React 包里刪掉。以后用的話不會(huì)報(bào)錯(cuò),但完全沒(méi)效果。
- 推薦:用 TypeScript 做靜態(tài)類型檢查,或者繼續(xù)用獨(dú)立的 prop-types 包(手動(dòng)檢查)。
- 默認(rèn)值統(tǒng)一用 ES6 默認(rèn)參數(shù),更簡(jiǎn)潔。
ref 現(xiàn)在可以直接作為 prop 傳(超級(jí)實(shí)用?。?以前,函數(shù)組件想接收 ref 必須裹一層 forwardRef:
// React 18 const MyInput = React.forwardRef((props, ref) => ( <input ref={ref} {...props} /> ));React 19 后,函數(shù)組件直接收 ref,像 children 一樣自然:
// React 19 function MyInput({ ref, ...props }) { return <input ref={ref} {...props} />; }少了好多樣板代碼,官方還提供了 codemod 自動(dòng)遷移。
其他 props 相關(guān)的小優(yōu)化:對(duì) Custom Elements(Web Components)的支持更好,props 會(huì)優(yōu)先作為 property 傳,而不是 attribute。
總之,React 19 的 props 更干凈、更貼近現(xiàn)代 JS。如果你還在用老項(xiàng)目,建議升級(jí)時(shí)跑一下官方 codemod。
四、React Props 的各種“邊界情況”詳解:不傳、傳了不用、沒(méi)給值會(huì)發(fā)生什么?
在實(shí)際寫代碼時(shí),props 的這些“邊緣情況”經(jīng)常讓人摸不著頭腦。今天我們就一個(gè)個(gè)拆開(kāi)看,結(jié)合真實(shí)代碼和控制臺(tái)輸出,告訴你到底會(huì)發(fā)生什么,以及怎么避免坑。
1. 不傳某個(gè) prop(完全沒(méi)寫)
情況:父組件使用子組件時(shí),壓根沒(méi)寫這個(gè) prop。
結(jié)果:子組件收到這個(gè) prop 的值是 undefined。
例子:
子組件 Greeting.jsx:
function Greeting({ name, message, showIcon }) {
console.log({ name, message, showIcon }); // 關(guān)鍵看這里
return (
<div>
<h1>Hello {name}</h1>
<p>{message}</p>
{showIcon && <span>??</span>}
</div>
);
}
父組件這樣用:
<Greeting />
控制臺(tái)輸出:
{ name: undefined, message: undefined, showIcon: undefined }
頁(yè)面顯示:
Hello // 空
// 空
結(jié)論:不傳 = undefined,不會(huì)報(bào)錯(cuò),但顯示會(huì)很丑。
2. 傳了 prop 但子組件沒(méi)用(寫了但沒(méi)解構(gòu)/使用)
情況:父組件傳了值,但子組件參數(shù)里沒(méi)接收它。
結(jié)果:傳的值會(huì)丟失,子組件根本拿不到。
例子:
父組件:
<Greeting name="小明" message="歡迎" />
子組件故意不接收 name:
function Greeting({ message }) { // 只解構(gòu)了 message,name 被忽略
console.log({ message });
return <h1>Hello {message}</h1>;
}
控制臺(tái)輸出:
{ message: "歡迎" }
name 的值“小明”直接丟了,子組件完全不知道有這個(gè) prop。
另一種寫法(用 props 對(duì)象):
function Greeting(props) {
console.log(props); // { name: "小明", message: "歡迎" }
return <h1>Hello {props.message}</h1>; // 只用了 message
}
這種情況下 props 對(duì)象里是有 name 的,但如果你沒(méi)用它,就白傳了。
結(jié)論:傳了但沒(méi)用 = 白傳,浪費(fèi)性能(輕微),代碼易混淆。
3. 傳了 prop 但沒(méi)給值()
情況:寫了 prop 名,但沒(méi)賦值(布爾類型常見(jiàn))。
結(jié)果:React 會(huì)自動(dòng)把這個(gè) prop 的值設(shè)為 true。
例子:
父組件:
<Greeting showIcon /> // 沒(méi)寫 =true
<Greeting showIcon={true} /> // 顯式寫 true
<Greeting showIcon={false} />// 顯式寫 false
子組件:
function Greeting({ showIcon }) {
console.log({ showIcon });
return showIcon && <span>??</span>;
}
三種寫法的控制臺(tái)輸出:
{ showIcon: true } // <Greeting showIcon />
{ showIcon: true } // <Greeting showIcon={true} />
{ showIcon: false } // <Greeting showIcon={false} />
結(jié)論:在 JSX 中, 等價(jià)于 。這是 React 的語(yǔ)法糖,超級(jí)常見(jiàn)于開(kāi)關(guān)類 prop(如 disabled、checked、selected 等)。
4. 給了默認(rèn)值的情況(ES6 默認(rèn)參數(shù))
情況:不傳或傳 undefined 時(shí),用默認(rèn)值兜底。
例子:
function Greeting({
name = "陌生人",
message = "歡迎光臨",
showIcon = false
}) {
console.log({ name, message, showIcon });
return (
<div>
<h1>Hello {name}</h1>
<p>{message}</p>
{showIcon && <span>??</span>}
</div>
);
}
測(cè)試幾種調(diào)用:
<Greeting /> // 全不傳
<Greeting name={undefined} /> // 顯式傳 undefined
<Greeting name="" /> // 傳空字符串(不會(huì)用默認(rèn))
<Greeting name="小明" />
控制臺(tái)輸出:
{ name: "陌生人", message: "歡迎光臨", showIcon: false }
{ name: "陌生人", message: "歡迎光臨", showIcon: false } // undefined 觸發(fā)默認(rèn)
{ name: "", message: "歡迎光臨", showIcon: false } // 空字符串不會(huì)觸發(fā)默認(rèn)
{ name: "小明", message: "歡迎光臨", showIcon: false }
關(guān)鍵點(diǎn):只有 undefined 才會(huì)觸發(fā) ES6 默認(rèn)值。傳 null、""、false、0 都不會(huì)觸發(fā)默認(rèn)值。
5. 總結(jié)表格(一目了然)
| 父組件寫法 | 子組件收到值 | 是否觸發(fā)默認(rèn)值 | 說(shuō)明 |
|---|---|---|---|
| 不寫 prop | undefined | 是 | 最常見(jiàn)坑 |
| < Comp flag /> | true | - | 布爾 prop 的語(yǔ)法糖 |
| < Comp flag={true/false} /> | true / false | - | 顯式控制 |
| < Comp name={undefined} /> | undefined | 是 | 顯式傳 undefined 也會(huì)觸發(fā)默認(rèn) |
| < Comp name="" /> | ""(空字符串) | 否 | 傳了具體值,就不會(huì)用默認(rèn) |
| < Comp name={null} /> | null | 否 | null 是合法值,不會(huì)觸發(fā)默認(rèn) |
| 傳了 prop 但子組件沒(méi)接收 | 拿不到(丟失) | - | 代碼 bug,建議用 TS 或 PropTypes 檢查 |
五、children:最強(qiáng)大的 props
children 是 React 自動(dòng)傳給你的一個(gè)特殊 prop,代表組件標(biāo)簽之間的內(nèi)容。它讓組件超級(jí)靈活,能“插槽”任意 JSX。
Card 組件:
App.jsx <Card className="user-card"> <h2>張三</h2> <p>高級(jí)前端工程師</p> <button>查看詳情</button> </Card>
Card 實(shí)現(xiàn):
//Card.jsx
const Card = ({ children, className = "" }) => {
return <div className={`card ${className}`}>{children}</div>;
};
其中,{children}就是
<h2>張三</h2> <p>高級(jí)前端工程師</p> <button>查看詳情</button>
直接把父組件傳的 JSX 原樣渲染出來(lái),完美封裝卡片樣式。
Modal 組件(更高級(jí)的定制): 我們想讓 Modal 支持自定義 header 和 footer:
//App.jsx
<Modal HeaderComponent={MyHeader} FooterComponent={MyFooter}>
<p>這是一個(gè)彈窗</p>
<p>你可以在這里顯示任何JSX</p>
</Modal>
Modal 實(shí)現(xiàn):
//Modal.jsx
function Modal({ HeaderComponent, FooterComponent, children }) {
return (
<div style={styles.overlay}>
<div style={styles.modal}>
<HeaderComponent />
<div style={styles.content}>{children}</div>
<FooterComponent />
</div>
</div>
);
}
這里 children 就是彈窗正文內(nèi)容,而 Header/Footer 是通過(guò) props 傳組件,實(shí)現(xiàn)高度定制。
children 的威力在于:它讓你的組件像“容器”一樣,能包裹任意內(nèi)容。Ant Design、Material UI 的很多組件都靠它實(shí)現(xiàn)靈活性。
六、React 中常見(jiàn)的 CSS 樣式寫法
React 是“CSS in JS”的鼻祖,樣式寫法靈活多變。來(lái)看幾種常見(jiàn)方式,各有優(yōu)缺點(diǎn):
內(nèi)聯(lián)樣式(style 對(duì)象) —— 最簡(jiǎn)單,直接在 JSX 里寫
<h2 style={{ margin: 0, color: "blue" }}>自定義標(biāo)題</h2>適合快速原型或動(dòng)態(tài)樣式(比如根據(jù) props 變色)。缺點(diǎn):沒(méi)法用偽類(如 :hover),寫多了很亂。
單獨(dú) CSS 文件 + className —— 傳統(tǒng)方式,最常見(jiàn) 看 Card.jsx 和 Card.css:
import "./Card.css"; const Card = ({ children, className = "" }) => { return <div className={`card ${className}`}>{children}</div>; };CSS 文件里寫:
.card { background-color: #ffffff; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); /* ... */ } .card:hover { transform: translateY(-4px); /* 懸停效果 */ }優(yōu)點(diǎn):支持所有 CSS 特性(偽類、媒體查詢),易維護(hù)。缺點(diǎn):類名沖突風(fēng)險(xiǎn)(可以用 CSS Modules 解決)。
CSS in JS(對(duì)象樣式)
const styles = { overlay: { backgroundColor: "rgba(0,0,0,0.5)", /* ... */ }, modal: { backgroundColor: "white", /* ... */ }, }; <div style={styles.overlay}>...</div>優(yōu)點(diǎn):樣式作用域天然隔離,動(dòng)態(tài)樣式超方便。缺點(diǎn):運(yùn)行時(shí)開(kāi)銷稍大,偽類支持差(需要額外庫(kù)如 styled-components)。
其他流行方案:
- styled-components 或 emotion:寫模板字符串,兼顧作用域和偽類。
- Tailwind CSS:utility-first,直接在 className 里堆類。
- CSS Modules:自動(dòng)生成唯一類名,避免沖突。
個(gè)人建議:小項(xiàng)目?jī)?nèi)聯(lián)或單獨(dú) CSS 夠用,中大型項(xiàng)目推薦 CSS Modules + Tailwind,或者 styled-components。
最后總結(jié)
props 是 React 的靈魂,掌握它你就掌握了組件通信。默認(rèn)值、類型檢查、children 這些細(xì)節(jié)用好了,代碼會(huì)優(yōu)雅很多。React 19 把一些老古董清理掉,鼓勵(lì)我們寫更現(xiàn)代的代碼(ES6 默認(rèn) + TS)。
到此這篇關(guān)于React父?jìng)髯拥膯雾?xiàng)數(shù)據(jù)流props的使用的文章就介紹到這了,更多相關(guān)React 單項(xiàng)數(shù)據(jù)流props內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react+antd實(shí)現(xiàn)動(dòng)態(tài)編輯表格數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了react+antd實(shí)現(xiàn)動(dòng)態(tài)編輯表格數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
詳解webpack + react + react-router 如何實(shí)現(xiàn)懶加載
這篇文章主要介紹了詳解webpack + react + react-router 如何實(shí)現(xiàn)懶加載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-11-11
使用React路由實(shí)現(xiàn)頁(yè)面導(dǎo)航的示例代碼
在構(gòu)建現(xiàn)代Web應(yīng)用程序時(shí),前端路由是一個(gè)不可或缺的部分,今天,我們將討論如何在React中使用React Router來(lái)實(shí)現(xiàn)頁(yè)面導(dǎo)航,在這篇博客中,我們將會(huì)探索路由的基本概念,設(shè)置React Router,并通過(guò)示例代碼來(lái)展示如何實(shí)現(xiàn)復(fù)雜的頁(yè)面導(dǎo)航,需要的朋友可以參考下2025-02-02
React18使用Echarts和MUI實(shí)現(xiàn)一個(gè)交互性的溫度計(jì)
這篇文章我們將結(jié)合使用React 18、Echarts和MUI(Material-UI)庫(kù),展示如何實(shí)現(xiàn)一個(gè)交互性的溫度計(jì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
react項(xiàng)目初始化時(shí)解析url路徑中的動(dòng)態(tài)片段實(shí)現(xiàn)方案
本文將深入探討React項(xiàng)目初始化階段如何高效解析URL路徑中的動(dòng)態(tài)片段,實(shí)現(xiàn)優(yōu)雅的路由參數(shù)處理,幫助開(kāi)發(fā)者構(gòu)建更靈活的應(yīng)用程序,感興趣的朋友一起看看吧2025-07-07
react中antd Upload手動(dòng)上傳的示例
本文主要介紹了react中antd Upload手動(dòng)上傳的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04

