React 19 新特性详解:提升开发效率与性能

React 19 是 React 生态系统的一次重大更新,引入了多项新特性和改进,旨在简化开发流程、提升应用性能,并优化用户体验。

总结

  1. compiler
  2. use()
  3. useOptimistic
  4. useFormStatus、useFormState
  5. Server Components
  6. Directives
  7. Suspense
  8. forwardRef改进

第一点 React Compiler:自动优化,告别手动 Memoization

心智负担瞬间少了一半。

React 19 引入了全新的编译器,能够自动优化 React 代码,减少开发者手动使用 useMemouseCallbackmemo 的需求。编译器将 React 代码转换为高效的 JavaScript,提升性能并简化代码。

js 复制代码
const ExpensiveComponent = () => {
  const [count, setCount] = useState(0);
  const expensiveCalculation = useMemo(() => {
    let sum = 0;
    for (let i = 0; i < 1000000000; i++) sum += i;
    return sum;
  }, [count]);

  return <div>{expensiveCalculation}</div>;
};

React 18:需要手动优化,需自己添加useMemo

js 复制代码
const ExpensiveComponent = () => {
  const [count, setCount] = useState(0);
  const expensiveCalculation = () => {
    let sum = 0;
    for (let i = 0; i < 1000000000; i++) sum += i;
    return sum;
  };

  return <div>{expensiveCalculation}</div>;
};

React 19:自动优化。解释 :React 19 的编译器会自动处理性能优化,开发者无需再手动编写 useMemouseCallback

第二点 use() Hook:简化异步操作与 Context 消费

use() 是 React 19 引入的一个多功能 Hook,用于处理异步操作(如数据获取)和 Context 消费。它可以替代 useEffectuseContext,使代码更加简洁。

js 复制代码
// React 18:手动管理异步状态
const DataFetchingComponent = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchData().then(setData).catch(setError).finally(() => setLoading(false));
  }, []);

  if (loading) return <p>加载中...</p>;
  if (error) return <p>错误: {error}</p>;
  return <div>{JSON.stringify(data)}</div>;
};

// React 19:使用 `use()`
const DataFetchingComponent = () => {
  const data = use(fetchData());
  return <div>{JSON.stringify(data)}</div>;
};

解释use() 会在 Promise 解析前挂起组件,并自动处理错误边界,简化了异步操作的管理。

js 复制代码
import { createContext, use } from 'react';

// 创建一个上下文
const ThemeContext = createContext('light');

function ThemedButton() {
  // 使用 use 消费上下文数据
  const theme = use(ThemeContext);

  return (
    <button style={{ background: theme === 'dark' ? '#333' : '#eee', color: theme === 'dark' ? '#fff' : '#000' }}>
      当前主题: {theme}
    </button>
  );
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}

export default App;
js 复制代码
// 使用 useContext
import { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button>当前主题: {theme}</button>;
}

// 使用 use
import { createContext, use } from 'react';

const ThemeContext = createContext('light');

function ThemedButton() {
  const theme = use(ThemeContext);
  return <button>当前主题: {theme}</button>;
}

解释:用use,不用useContext拿上下文了。use替代了useContext

第三点 useOptimistic:乐观更新,提升用户体验

useOptimistic 允许开发者在异步操作完成前立即更新 UI,提供即时反馈,从而提升用户体验。这在聊天应用或表单提交中非常有用。

js 复制代码
function ChatApp() {
  const [messages, setMessages] = useState([]);
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(messages, (state, newMessage) => [
    ...state,
    { text: newMessage, sending: true },
  ]);
  
  const handleSubmit = async (message) => {
    addOptimisticMessage(message);
    await serverAPI(message); // 模拟服务器请求
    setMessages((prev) => [...prev, { text: message, sending: false }]);
  };
  
  return (
    <div>
      {optimisticMessages.map((msg, index) => (
        <div key={index}>{msg.text} {msg.sending && <small>(发送中...)</small>}</div>
      ))}
      <input type="text" onBlur={(e) => handleSubmit(e.target.value)} />
    </div>
  );
}

解释useOptimistic 会在服务器响应前更新 UI,如果请求失败,则自动回滚状态。

第四点 useFormStatususeFormState:简化表单管理

React 19 引入了 useFormStatususeFormState,用于简化表单状态管理和提交逻辑。useFormStatus 可以获取表单的提交状态,而 useFormState 则用于管理表单的状态。

js 复制代码
// useFormStatus:获取表单提交状态
function SubmitButton() {
  const { pending } = useFormStatus();
  return <button disabled={pending}>{pending ? "提交中..." : "提交"}</button>;
}

// useFormState:管理表单状态
function MyForm() {
  const [state, formAction] = useFormState(async (prevState, formData) => {
    const name = formData.get("name");
    if (!name) return { error: "Name is required" };
    return { message: `Hello, ${name}!` };
  }, null);

  return (
    <form action={formAction}>
      <input type="text" name="name" />
      <SubmitButton />
      {state?.error && <p>{state.error}</p>}
      {state?.message && <p>{state.message}</p>}
    </form>
  );
}

解释useFormStatususeFormState 简化了表单的状态管理和提交逻辑,减少了样板代码。

第五点 Server Components:服务端渲染的进一步优化

React 19 将 Server Components 推向稳定,允许在服务器端提前渲染组件,减少客户端的渲染负担,提升页面加载速度。

js 复制代码
// Server Component
export default function ServerComponent() {
  const data = fetchDataFromServer(); // 服务器端数据获取
  return <div>{data}</div>;
}

// 客户端引用
import ServerComponent from './ServerComponent';
function ClientComponent() {
  return (
    <div>
      <ServerComponent />
    </div>
  );
}

第六点 Directives:简化组件配置

React 19 引入了 use clientuse server 指令,用于声明客户端或服务器端组件,简化了组件配置。

js 复制代码
"use client";
function ClientComponent() {
  return <div>客户端渲染</div>;
}

"use server";
function ServerComponent() {
  return <div>服务器端渲染</div>;
}

解释:通过指令声明组件类型,简化了配置并提升了代码可读性

第七点 Suspense

Suspense 是一个用于处理异步操作(如数据获取、代码分割等)的特性。它允许开发者在组件等待异步操作完成时,显示一个占位符(fallback)。

js 复制代码
import React, { Suspense } from 'react';

// 使用 React.lazy 动态加载组件
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>加载中...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  );
}

export default App;

解释

  • React.lazy 用于动态加载组件。
  • <Suspense> 包裹异步组件,并在加载过程中显示 fallback 内容。
js 复制代码
import React, { Suspense } from 'react';

// 模拟一个支持 Suspense 的数据获取函数
function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => resolve("数据加载完成!"), 2000);
  });
}

// 使用 Suspense 获取数据
const resource = fetchData();

function DataComponent() {
  const data = resource.read(); // 假设这是一个支持 Suspense 的读取方法
  return <div>{data}</div>;
}

function App() {
  return (
    <div>
      <Suspense fallback={<div>加载数据中...</div>}>
        <DataComponent />
      </Suspense>
    </div>
  );
}

export default App;

解释

  • fetchData 是一个模拟的异步数据获取函数。
  • resource.read() 是一个支持 Suspense 的读取方法(需要数据获取库支持)。
  • 如果数据未加载完成,Suspense 会显示 fallback
js 复制代码
import React, { Suspense, useState } from 'react';

function fetchData(id) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(`数据 ${id} 加载完成!`), 2000);
  });
}

function DataComponent({ id }) {
  const data = fetchData(id).read(); // 假设这是一个支持 Suspense 的读取方法
  return <div>{data}</div>;
}

function App() {
  const [id, setId] = useState(1);

  return (
    <div>
      <button onClick={() => setId(id + 1)}>加载下一个数据</button>
      <Suspense fallback={<div>加载中...</div>}>
        <DataComponent id={id} />
      </Suspense>
    </div>
  );
}

export default App;

解释

  • 当用户点击按钮时,React 会在后台加载新数据,同时继续显示当前 UI。
  • 数据加载完成后,Suspense 会更新 UI。

第八点 forwardRef 改进

19之前的用法:

js 复制代码
import React, { forwardRef, useRef } from 'react';

// 子组件:使用 forwardRef 接收 ref
const Input = forwardRef((props, ref) => {
  return <input type="text" ref={ref} {...props} />;
});

// 父组件
function App() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <Input ref={inputRef} />
      <button onClick={focusInput}>聚焦输入框</button>
    </div>
  );
}

export default App;

解释

  • Input 组件使用 forwardRef 接收 ref,并将其传递给 <input> 元素。
  • 父组件通过 ref 直接操作子组件的 DOM 元素。

19改进的用法:

js 复制代码
import React, { useRef } from 'react';

// 子组件:直接接收 ref 作为 prop
function Input({ ref, ...props }) {
  return <input type="text" ref={ref} {...props} />;
}

// 父组件
function App() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <Input ref={inputRef} />
      <button onClick={focusInput}>聚焦输入框</button>
    </div>
  );
}

export default App;

解释

  • 在 React 19 中,ref 可以直接作为 prop 传递给子组件,无需使用 forwardRef
  • React 会自动处理 ref 的传递。
js 复制代码
import React, { useRef } from 'react';

// 子组件:提供默认 ref 值
function Input({ ref = useRef(null), ...props }) {
  return <input type="text" ref={ref} {...props} />;
}

// 父组件
function App() {
  return (
    <div>
      <Input />
    </div>
  );
}

export default App;

解释

  • 如果父组件没有传递 ref,子组件会使用默认的 ref 值。
js 复制代码
import React, { forwardRef, useRef } from 'react';

// 高阶组件
function withLogging(WrappedComponent) {
  return forwardRef((props, ref) => {
    console.log('组件被渲染了');
    return <WrappedComponent ref={ref} {...props} />;
  });
}

// 普通组件
function Input({ ref, ...props }) {
  return <input type="text" ref={ref} {...props} />;
}

// 使用高阶组件包裹 Input
const InputWithLogging = withLogging(Input);

// 父组件
function App() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <InputWithLogging ref={inputRef} />
      <button onClick={focusInput}>聚焦输入框</button>
    </div>
  );
}

export default App;

解释

  • withLogging 是一个高阶组件,使用 forwardRef 确保 ref 被正确传递到 Input 组件。

总结

  1. compiler ------ 自动优化,无需手动加useCallbackuseMemomemo
  2. use() ------ 用use替代useContextuseEffect
  3. useOptimistic ------ 乐观做事,慢的时候,先提示用户不让用户干等。
  4. useFormStatus、useFormState ------ 表单的钩子:status获取状态,state一个获取数据。
  5. Server Components ------ 服务器端提前渲染组件,减少客户端渲染工作量,提高性能,做seo优化很好用。
  6. Directives ------ 混合渲染,用来区分服务器端的代码和客户端代码,提高可读性。
  7. Suspense ------ 占位,加载的过程,先提示,回来东西再渲染正文。
  8. forwardRef改进 ------ 可不用forwardRef,直接用props拿值。
相关推荐
大土豆的bug记录3 小时前
鸿蒙进行视频上传,使用 request.uploadFile方法
开发语言·前端·华为·arkts·鸿蒙·arkui
maybe02093 小时前
前端表格数据导出Excel文件方法,列自适应宽度、增加合计、自定义文件名称
前端·javascript·excel·js·大前端
HBR666_3 小时前
菜单(路由)权限&按钮权限&路由进度条
前端·vue
A-Kamen3 小时前
深入理解 HTML5 Web Workers:提升网页性能的关键技术解析
前端·html·html5
锋小张5 小时前
a-date-picker 格式化日期格式 YYYY-MM-DD HH:mm:ss
前端·javascript·vue.js
鱼樱前端5 小时前
前端模块化开发标准全面解析--ESM获得绝杀
前端·javascript
yanlele6 小时前
前端面试第 75 期 - 前端质量问题专题(11 道题)
前端·javascript·面试
前端小白۞7 小时前
el-date-picker时间范围 编辑回显后不能修改问题
前端·vue.js·elementui
拉不动的猪7 小时前
刷刷题44(uniapp-中级)
前端·javascript·面试
Spider Cat 蜘蛛猫7 小时前
chrome插件开发之API解析-chrome.scripting.executeScript()
前端·chrome