在 React 开发中,组件传参 和路由跳转传参 是最核心、最常用的技能,也是新手最容易混淆的知识点。本文会用最通俗的语言、完整可复制的代码,把所有传参方式讲透,覆盖父子组件、兄弟组件、跨级组件、路由页面全场景,看完直接上手开发
一、前置说明
本文基于:
- React 18+
- React Router 6+(路由最新版,无兼容问题)
- 函数式组件 + Hooks(官方推荐写法)
二、React 组件传参(组件间数据通信)
组件传参分为四大场景:
- 父组件 → 子组件(最基础)
- 子组件 → 父组件
- 兄弟组件传参
- 跨级组件传参(多层嵌套)
场景 1:父组件 → 子组件传参(props)
核心 :父组件通过自定义属性传值,子组件通过 props 接收。
代码示例
javascript
// 父组件 Parent.jsx
import Child from './Child';
function Parent() {
// 定义要传递的数据
const userInfo = { name: 'React新手', age: 20 };
const msg = '来自父组件的问候';
return (
<div>
<h2>我是父组件</h2>
{/* 直接通过属性传参 */}
<Child user={userInfo} message={msg} />
</div>
);
}
export default Parent;
// 子组件 Child.jsx
// 直接解构 props 接收
function Child({ user, message }) {
return (
<div>
<h3>我是子组件</h3>
<p>姓名:{user.name}</p>
<p>年龄:{user.age}</p>
<p>消息:{message}</p>
</div>
);
}
export default Child;
特点:
- 最简单、最常用
- 只能父传子,不能反向传递
场景 2:子组件 → 父组件传参(回调函数)
核心 :父组件给子组件传一个函数,子组件调用这个函数并把数据当参数传回。
代码示例
javascript
// 父组件 Parent.jsx
import { useState } from 'react';
import Child from './Child';
function Parent() {
const [childData, setChildData] = useState('');
// 定义接收子组件数据的函数
const getChildData = (data) => {
setChildData(data);
};
return (
<div>
<h2>父组件接收:{childData}</h2>
{/* 把函数传给子组件 */}
<Child sendData={getChildData} />
</div>
);
}
export default Parent;
// 子组件 Child.jsx
function Child({ sendData }) {
const handleClick = () => {
// 调用父组件函数,传参回去
sendData('我是子组件的数据!');
};
return (
<button onClick={handleClick}>点我给父组件传参</button>
);
}
export default Child;
场景 3:兄弟组件传参
核心 :状态提升 → 把数据放到共同的父组件中,通过父组件中转。
流程:兄弟A → 父组件 → 兄弟B
代码示例
javascript
// 父组件 Parent.jsx
import { useState } from 'react';
import BrotherA from './BrotherA';
import BrotherB from './BrotherB';
function Parent() {
const [msg, setMsg] = useState('');
return (
<div>
{/* A 传数据给父组件 */}
<BrotherA setMsg={setMsg} />
{/* 父组件把数据传给 B */}
<BrotherB msg={msg} />
</div>
);
}
export default Parent;
// BrotherA.jsx(发送方)
function BrotherA({ setMsg }) {
return (
<button onClick={() => setMsg('A传给B的消息')}>
点我传给兄弟B
</button>
);
}
// BrotherB.jsx(接收方)
function BrotherB({ msg }) {
return <p>B 收到:{msg}</p>;
}
场景 4:跨级组件传参(Context)
当组件嵌套很深(如 父→子→孙→曾孙),用 props 一层层传太麻烦,用 Context 直接跨级传参。
代码示例
javascript
// 1. 创建上下文 Context.js
import { createContext } from 'react';
export const MyContext = createContext();
// 2. 顶层组件(祖先)
import { MyContext } from './Context';
import Child from './Child';
function GrandParent() {
const user = { name: '跨级传参', id: 1001 };
return (
// 提供数据
<MyContext.Provider value={user}>
<Child />
</MyContext.Provider>
);
}
// 3. 底层组件(后代,任意层级)
import { useContext } from 'react';
import { MyContext } from './Context';
function GrandSon() {
// 直接接收跨级数据
const user = useContext(MyContext);
return <p>曾孙收到:{user.name}</p>;
}
适用场景:全局主题、用户信息、多层级共享数据。
三、React Router 6 路由跳转传参
路由传参用于页面之间跳转时传递数据,比如从列表页跳转到详情页,带过去 id、标题等。
React Router 6 有 3 种最常用传参方式:
方式 1:路由参数 / 动态路由(推荐)
场景 :传递 id 等必须参数,URL 显示:/detail/123
步骤 1:配置路由
javascript
// 路由配置
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import List from './List';
import Detail from './Detail';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/list" element={<List />} />
{/* 定义动态参数 :id */}
<Route path="/detail/:id" element={<Detail />} />
</Routes>
</BrowserRouter>
);
}
步骤 2:跳转传参(两种方式)
方式 A:声明式跳转(Link)
javascript
import { Link } from 'react-router-dom';
function List() {
return (
<Link to="/detail/1001">跳转到详情页(带参数id=1001)</Link>
);
}
方式 B:编程式导航(useNavigate)
javascript
import { useNavigate } from 'react-router-dom';
function List() {
const navigate = useNavigate();
return (
<button onClick={() => navigate('/detail/1001')}>
编程式跳转传参
</button>
);
}
步骤 3:接收参数
javascript
import { useParams } from 'react-router-dom';
function Detail() {
// 获取路由上的 id
const { id } = useParams();
return <h2>详情页 ID:{id}</h2>;
}
方式 2:查询参数(?key=value)
场景 :传递可选参数,URL 显示:/search?keyword=react&page=1
跳转传参
javascript
// 方式1:Link
<Link to="/search?keyword=react&page=1">搜索页</Link>
// 方式2:编程式
navigate('/search?keyword=react&page=1');
接收参数
javascript
import { useSearchParams } from 'react-router-dom';
function Search() {
const [searchParams] = useSearchParams();
// 获取参数
const keyword = searchParams.get('keyword');
const page = searchParams.get('page');
return (
<div>
<p>关键词:{keyword}</p>
<p>页码:{page}</p>
</div>
);
}
方式 3:隐式传参(state,不显示在 URL)
场景 :传递对象、大量数据,不希望暴露在 URL 上。
跳转传参
javascript
// 1. Link 方式
<Link
to="/detail"
state={{ id: 1001, title: '隐式传参', content: '我不显示在URL里' }}
>
隐式传参跳转
</Link>
// 2. 编程式
navigate('/detail', {
state: { id: 1001, title: '隐式传参' }
});
接收参数
javascript
import { useLocation } from 'react-router-dom';
function Detail() {
const location = useLocation();
// 获取隐式参数
const data = location.state;
return (
<div>
<p>ID:{data.id}</p>
<p>标题:{data.title}</p>
</div>
);
}
四、3 种路由传参对比
| 传参方式 | URL 显示 | 数据类型 | 刷新页面 | 适用场景 |
|---|---|---|---|---|
| 动态路由(/:id) | 显示 | 字符串 | 保留 | 必选参数(id) |
| 查询参数(?key=val) | 显示 | 字符串 | 保留 | 可选参数(分页、搜索) |
| 隐式 state | 不显示 | 任意类型 | 保留 | 对象、敏感数据、大量数据 |
五、总结
-
组件传参
- 父→子:
props - 子→父:
回调函数 - 兄弟:
状态提升(父组件中转) - 跨级:
Context
- 父→子:
-
路由传参
- 必选 id:
/detail/:id+useParams - 可选参数:
?key=val+useSearchParams - 对象 / 隐式数据:
state+useLocation
- 必选 id:
六、小建议
- 简单组件传参:优先用 props / 回调函数
- 多页面传参:优先用 路由动态参数 + state
- 全局共享数据:再用 Context / Redux / Zustand
总结
- 组件传参 核心:父传子用
props、子传父用回调函数 、跨级用Context; - 路由传参 核心:动态路由传
id、查询参数传可选值、state隐式传对象;