React18和React19新特性

React18核心并发渲染

通过createRoot、useTransition、自动批处理等特性提升应用性能和用户体验,向下兼容,升级成本低

1. 并发渲染(Concurrent Rendering) ---- 底层核心

  • 它允许React的渲染过程被中断、暂停、恢复或放弃,不再是过去"一旦开始就必须执行到底"的同步渲染模式
  • 核心价值:解决长任务阻塞主线程导致的界面卡顿(如大数据渲染、复杂计算时,输入/点击等交互仍能响应)
  • 注意:这是底层能力,无需开发者直接调用,通过后续的useTransition、createRoot等API间接启用

2. 新的根节点API: createRoot(启用新特性的入口)

  • 18废弃了旧的ReactDOM.render,推出createRoot作为新的根节点创建方式,这是启用所有18新特性的前提
javascript 复制代码
// 17及之前
import ReactDOM from 'react-dom'
ReactDOM.render(<APP />, document.getElementById('root'))

// 18推荐
import ReactDOM from 'react-dom/client'
const root = ReactDOM.createRoot(document.getElementById('root))
root.render(<APP />) // 首次渲染
root.unmount() // 新增:优雅卸载组件(替代旧的unmountComponentAtNode)

3. 自动批处理(Automatic Batching) --- 性能优化

  • 批处理值React合并多个状态更新,只触发一次重渲染,减少不必要的DOM操作
  • 18把批处理能力扩展到所有场景(包括异步回调、定时器、Promise等)
scss 复制代码
// 17 异步回调中会触发2次重渲染
function handleClick(){
	fetch('/api/data').then(() => {
		setCount(c => c + 1)
		setFlag(f => !f)
	})
}
// 18 自动批处理,仅触发1次重渲染
// 无需手动修改代码,框架层面自动完成
// 如需禁用批处理:使用ReactDOM.flushSync(() => { setCount(1) })

4. useTransition --- 区分紧急/非紧急更新

  • 用于标记非紧急更新(如列表筛选、大数据渲染),避免阻塞紧急更新(如输入框打字、按钮点击)提升交互流畅度
javascript 复制代码
import { useTransition, useState } from 'react'
function SearchBox() {
	const [input, setInput] = useState('')
	const [list, setList] = useState([])
	const [isPending, startTransition]  = usetransition() // 加载态 + 标记非紧急更新
	
	const handleChange = (e) => {
		// 紧急更新:输入框内容(优先执行,不卡顿)
		setInput(e.target.value)
		// 非紧急更新:列表筛选(可被中断)
		startTransition(() => {
			const filtered = largeDataList.filter(item => item.includes(e.target.value))
			setList(filtered)
		})
	}
	return (
		<div>
			<input value={input} onChange={handleChange} />
 			{/* 非紧急更新时显示加载态 */}
      		{isPending ? <div>筛选中...</div> : list.map(item => <div key={item}>{item}</div>)}
		</div>
	)
}

5. useDeferredValue --- 延迟更新非紧急状态

  • 效果类似useTransition,但针对单个状态值,适合需要延迟同步的场景(如输入框联想词)
javascript 复制代码
import { useDeferredValue, useSate } form 'react'
function InputWithSuggestion() {
	// 延迟更新:suggestionValue会滞后与input,且更新不阻塞主线程
	const suggestionValue = useDeferredValue(input, {timeoutMs: 200})
	// 基于延迟值渲染联想词(不会阻塞输入)
	const suggestions = getSuggestions(suggestionValue)

	return(
		<div>
			<input value={input} onChange={(e) => setInput(e.target.value)} />
			<div> {suggestions.map(s => <div key={s}> {s} </div>)} </div>
		</div>
	)
}

6. Suspense增强---支持数据加载(实验性)

  • 18正式扩展Suspense的能力,从代码分割延伸到数据加载(需配合React Query、SWR等库或Next.js框架),实现等待数据时显示加载态
javascript 复制代码
import { Suspense } from 'react'
import DataComponent from './DataComponent'
function App() {
	return (
		<div>
			<h1>主内容</h1>
			{/* 数据加载完成前显示fallback */}
			<Suspense fallback={<div>加载数据中...</div>}>
				<DataComponent/>
			</Suspense>
		</div>
	)
}

7. 服务端渲染(SSR)优化

  • 18对SSR做了大幅升级
  • 流式SSR:逐步输出HTML内容,无需等待所有数据加载完成,提升首屏渲染速度
  • Suspense配合SSR:支持服务端渲染时的加载态显示,避免首屏空白

8.严格模式增强

  • 18的严格模式会模拟组件挂载-卸载-重新挂载的过程,检测非幂等的副作用(如未清理的定时器、重复的请求),帮助开发者写出更健壮的代码

React19核心是简化开发体验

通过Actions、use()钩子,乐观更新等特性减少样板代码,完善服务器组件,聚焦"更简洁、更原生"的开发模式

1. Actions(核心):统一状态更新与表单处理

  • 彻底重构了表单提交、异步操作的处理方式,替代了传统的useState + useEffect + 事件处理组合,内置了加载态、错误处理、异步兼容能力
  • 自动收集表单数据,无需手动维护onchange
  • 原生支持异步操作,自动管理加载/错误状态
  • 可结合Suspense实现加载态展示
javascript 复制代码
import { useActionState } from 'react';

// 定义 Action 函数(支持异步)
async function submitForm(prevState, formData) {
  // 自动获取表单数据,无需手动绑定
  const username = formData.get('username');
  const password = formData.get('password');

  // 模拟异步请求
  try {
    const res = await fetch('/api/login', {
      method: 'POST',
      body: JSON.stringify({ username, password }),
    });
    if (!res.ok) throw new Error('登录失败');
    return { success: true, error: null };
  } catch (err) {
    return { success: false, error: err.message };
  }
}

function LoginForm() {
  // useActionState 管理 Action 状态:初始值、Action函数、加载态
  const [state, formAction, isPending] = useActionState(
    submitForm,
    { success: false, error: null } // 初始状态
  );

  return (
    <form action={formAction}>
      <input name="username" placeholder="用户名" />
      <input name="password" type="password" placeholder="密码" />
      
      {/* 加载态 */}
      <button type="submit" disabled={isPending}>
        {isPending ? '登录中...' : '登录'}
      </button>
      
      {/* 错误提示 */}
      {state.error && <div style={{ color: 'red' }}>{state.error}</div>}
      {/* 成功提示 */}
      {state.success && <div style={{ color: 'green' }}>登录成功!</div>}
    </form>
  );
}

2. use()钩子:简化异步数据获取

  • 替代了useEffect + useState处理异步数据的模式,允许直接在组件体重消费Promise,配合Suspense实现简洁的一部加载逻辑,无需手动管理加载/完成状态
javascript 复制代码
import { use, Suspense } from 'react';

// 异步获取数据的函数
function fetchUser(userId) {
  return fetch(`/api/users/${userId}`).then(res => res.json());
}

// 消费异步数据的组件
function UserProfile({ userId }) {
  // 直接用 use() 消费 Promise,无需 useEffect
  const user = use(fetchUser(userId));
  return (
    <div>
      <h3>{user.name}</h3>
      <p>邮箱:{user.email}</p>
    </div>
  );
}

// 父组件(用 Suspense 处理加载态)
function App() {
  return (
    <div>
      <h1>用户信息</h1>
      <Suspense fallback={<div>加载用户数据中...</div>}>
        <UserProfile userId="123" />
      </Suspense>
    </div>
  );
}

3. useOptimistic:原生支持乐观更新

  • 乐观更新指:先更新UI反馈用户,再等待后端相应

  • 19内置了useOptimistic钩子,无需手动写临时状态,大幅简化点赞、表单提交等场景的体验优化

    import { useOptimistic, useActionState } from 'react' // 异步提交点赞的Action函数 async function toggleLike(prevState, postId) { await fetch(/api/posts/${postId}/like, {method: 'POST'}) return { liked: !prevState.liked } } function LikeButton({postId}) { // 基础状态管理 const [state, toggleLikeAction] = useActionState(toggleLike, {like: false}) // 乐观更新:先更新UI, 再等请求完成 const [optimisticState, addOptimistic] = useOptimistic( state, (currentState) => ({ ...currentState, liked: !currentState.liked }) ) const handleClick = () => { // 1.立即更新UI 乐观更新 addOptimistic() // 2.发送异步请求 togleLikeAction(postId) } return ( <button onclick={handleClick} style={{color: optimisticState.liked ? 'red' : 'black'}}> { optimisticState.liked ? '取消点赞' : '点赞'} ) }

4. 服务器组件(RSC)正式稳定

  • 19完善了服务器组件(Server Components)的规范和实现,明确区分

  • 服务器组件:运行在服务端,无交互、无副作用,可直接访问数据库,减少客户端包体积

  • 客户端组件:允许在浏览器,支持交互(如点击、输入),需显式标记'use client'

  • 核心价值

    • 减少客户端JS体积,提升首屏加载速度
    • 服务端直接获取数据,避免客户端跨域请求
    • 前后端逻辑复用更简单
  • 在Next.js中使用示例

    javascript 复制代码
    // 服务器组件(无需 'use client',默认运行在服务端)
    async function PostList() {
      // 直接在组件中获取数据(服务端执行,无跨域)
      const posts = await fetch('/api/posts').then(res => res.json());
      return (
        <div>
          {posts.map(post => (
            <PostItem key={post.id} post={post} />
          ))}
        </div>
      );
    }
    
    // 客户端组件(需显式标记,支持交互)
    'use client';
    function PostItem({ post }) {
      const [liked, setLiked] = useState(false);
      return (
        <div>
          <h3>{post.title}</h3>
          <button onClick={() => setLiked(!liked)}>
            {liked ? '已点赞' : '点赞'}
          </button>
        </div>
      );
    }

5. 实用改进

  • ref转发简化:无需forwardRef,直接通过ref属性传递给子组件,减少样板代码
  • 错误边界增强:支持捕获更多类型的错误(如异步错误),且使用更简单
  • 表单原生增强:支持formAction、formMethod等原生表单属性,无需手动绑定
  • TypeScrit优化:类型定义更精准,减少不必要的类型断言,提升类型推导体验
  • 严格模式改进:更友好的副作用检测,帮助开发者写出更健壮的代码
相关推荐
小码哥_常2 小时前
Android新航标:Navigation 3为何成为变革先锋?
前端
SuperEugene2 小时前
Vue状态管理扫盲篇:状态管理中的常见坑 | 循环依赖、状态污染与调试技巧
前端·vue.js·面试
骑着小黑马2 小时前
从 Electron 到 Tauri 2:我用 3.5MB 做了个音乐播放器
前端·vue.js·typescript
aykon2 小时前
DataSource详解以及优势
前端
Mintopia2 小时前
戴了 30 天智能手环后,我才发现自己一直低估了“睡眠”
前端
leolee182 小时前
react redux 简单使用
前端·react.js·redux
仰望星空的小猴子2 小时前
常用的Hooks
前端
天才熊猫君2 小时前
Vue Fragment 锚点机制
前端
米丘2 小时前
Git 常用操作命令
前端