React 组件间传参好痛苦?试试这一套"优雅组合拳":Context 与 Refs 实战

React 组件间传参好痛苦?试试这一套"优雅组合拳":Context 与 Refs 实战

阶段概述

这篇聊三个东西:Context API 怎么解决层层传参的噩梦、React 19 新出的 use API 用起来哪里比 useContext 顺手、以及 useRef 的两个实际用途------存跨渲染周期的数据,和直接操控 DOM 节点。


第一部分:跨组件共享 Context API

1. 属性钻孔 (Prop Drilling) 的架构痛点

React 是单向数据流,数据只能从父组件往下传。如果一个深层嵌套的组件需要顶层的数据,你得把这个数据作为 props,经过所有中间组件一层一层传下去------哪怕这些中间组件根本用不上它。

这就是 Prop Drilling,两个明显的问题:

  • 改一个字段,链路上所有中间文件都要跟着改,重构起来很痛苦。
  • 中间组件被迫接收跟自己没关系的数据,复用性基本废掉了。

2. React 19 对 Context 语法的大幅简化

Context API 的思路是在顶层"广播"数据,任意深度的后代组件都能直接订阅,不用经过中间层。

React 18 及之前的写法:

jsx 复制代码
<UserContext.Provider value={user}>
  <Header />
</UserContext.Provider>

React 19 的写法,.Provider 后缀直接去掉了:

jsx 复制代码
<UserContext value={user}>
  <Header />
</UserContext>

旧的 <Context.Provider> 写法在 React 19 里还能用,但属于向后兼容,后续主要版本会移除,官方也会提供迁移工具。

3. Context 配合 State 的独立 Provider 封装

真实项目里,通常把 Context 的创建、状态声明和业务方法单独封装在一个文件里,避免顶层 App.jsx 越来越臃肿:

jsx 复制代码
// UserContext.jsx
import React, { createContext, useState } from 'react';

export const UserContext = createContext();

export const UserProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  const login = () => setUser({ name: 'Alex' });
  const logout = () => setUser(null);

  return (
    <UserContext value={{ user, login, logout }}>
      {children}
    </UserContext>
  );
};

App.jsx 里只需要用 <UserProvider> 包一下,里面所有组件都能直接消费 user,不用再层层传参了。


第二部分:React 19 全新 use API 消费 Context

1. use API 是什么

之前消费 Context 只能用 useContext,而且必须在组件顶层无条件调用。React 19 加了 use API,用法很简单:

javascript 复制代码
import { use } from 'react';
const user = use(UserContext);

2. useuseContext 好在哪里

最大的区别:use 可以写在 if 语句或条件渲染里,useContext 不行。

标准的 React Hook 有一条铁规则------不能在条件分支或循环里调用,useContext 也不例外。use 打破了这个限制,这在实际业务里挺有用的:

jsx 复制代码
export default function Avatar({ showProfile }) {
  if (showProfile) {
    // 在 if 里调用 use 没问题;换成 useContext 这里会直接报错崩溃
    const { user } = use(UserContext);
    return <p>Welcome, {user.name}</p>;
  }
  return <p>Guest</p>;
}

useContext 在 React 19 里还是支持的,写新代码的话官方更推荐用 use


第三部分:Refs 与 useRef 逃生舱

1. useRef 的第一大用途:保存跨渲染周期的可变值

useRef 返回一个带 .current 属性的对象,在组件整个生命周期里保持同一个引用。关键点是:修改 .current 不会触发重新渲染。

用秒表来说明这个特性比较直观。实现计时器的启动和停止,需要保存 setInterval 返回的 intervalId

  • 用普通局部变量:组件一重渲染变量就重置了,clearInterval 找不到之前的 id,计时器停不掉。
  • useState 保存:每次存 id 都会触发一次重渲染,多余的渲染什么也没做。
  • useRefintervalRef.current = setInterval(...) 存起来,停止时 clearInterval(intervalRef.current),不触发渲染,干净。

2. useRef 的第二大用途:直接操纵 DOM 节点

在 JSX 元素上挂 ref 属性,React 渲染完成后会把真实 DOM 节点写进 current,然后你就能直接调 DOM API:

  • 自动聚焦输入框:inputRef.current.focus()
  • 滚动到视野内:containerRef.current.scrollIntoView()
  • 视频播放控制:videoRef.current.play() / .pause()
  • 测量元素尺寸:elementRef.current.getBoundingClientRect()

有一条要注意:ref 只做读取或交互控制,不要用它绕过 React 去改 DOM 结构,也不要强行改 input 的 value。一旦绕开了虚拟 DOM,React 下次渲染时会把你改的东西直接覆盖掉,或者产生数据和视图不一致的 bug,很难排查。


写在最后

到这里,我们用三篇文章把 React 19 的基础到进阶核心概念都过了一遍。从最开始的 JSX 语法规则,到中途让人头疼的 State 异步快照,再到最后的 Context 跨组件通信和 Refs 逃生舱,这套组合拳基本覆盖了你日常开发 80% 的场景。

React 19 带来的 use API 简化了 Context 的消费,也给了我们更多编写条件逻辑的自由。技术概念聊完了,接下来就是把这些拼图拼在一起,去写实际的业务代码。多踩几次 State 不更新的坑,多写几个自定义 Provider,这些机制自然就变成你的肌肉记忆了。

相关推荐
qq_419854052 小时前
空间网格管理器
前端·javascript·html
qingmiaozhuan2 小时前
电脑录屏没有声音还能补救吗?音频采集链路详解及4种技术方案
前端·电脑·音视频·开发工具·电脑录屏·电脑录屏软件
天若有情6733 小时前
Dev_Portfolio 个人主页html网页源码分享!!!
前端·html·源码·个人主页
李剑一3 小时前
ant-design-vue 1.x 版本换肤功能开发
前端·vue.js·ant design
京东云开发者3 小时前
【Coding生态】从代码托管到 AI 能力底座:与Coding一起共建 AI 研发生态
前端
guhy fighting4 小时前
x-www-form-urlencoded,form-data,raw 表单请求格式的区别
前端·表单请求格式
李明卫杭州4 小时前
Vue2 与 Vue3 自定义指令详解:钩子变化、迁移指南与实战示例
前端·javascript·vue.js
问商十三载4 小时前
大模型GEO内容更新频率:3个节奏规律提收录权重,零成本提30%引用率附更新计划表
前端·人工智能·机器学习
yingyima4 小时前
sed 命令速查手册:从一次午夜事故说起
前端