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拿值。
相关推荐
GalenWu3 小时前
对象转换为 JSON 字符串(或反向解析)
前端·javascript·微信小程序·json
GUIQU.3 小时前
【Vue】微前端架构与Vue(qiankun、Micro-App)
前端·vue.js·架构
数据潜水员3 小时前
插槽、生命周期
前端·javascript·vue.js
2401_837088503 小时前
CSS vertical-align
前端·html
优雅永不过时·3 小时前
实现一个漂亮的Three.js 扫光地面 圆形贴图扫光
前端·javascript·智慧城市·three.js·贴图·shader
CodeCraft Studio5 小时前
报表控件stimulsoft教程:使用 JoinType 关系参数创建仪表盘
前端·ui
春天姐姐6 小时前
vue知识点总结 依赖注入 动态组件 异步加载
前端·javascript·vue.js
互联网搬砖老肖6 小时前
Web 架构之数据读写分离
前端·架构·web
钢铁男儿7 小时前
C# 方法(值参数和引用参数)
java·前端·c#
阿金要当大魔王~~7 小时前
面试问题(连载。。。。)
前端·javascript·vue.js