React19新特性大揭秘:useOptimistic如何优化你的开发体验?

94 阅读5分钟

会持续跟新技术干货,感谢大家支持,欢迎点赞、评论、留言。公众号同名【码间舞】

React是一个非常收欢迎的前端框架,国内外的一大群开发者用户,截止本文写作时为止,react的官方star是237K,周下载量也是稳步上升,在前端三大框架里面是最高的。而作为最受欢迎的框架之一,他的每次更新也牵动着万千开发者的内心。

image.png

我会整理出一些react19新的特性、新的api给大家详细分析以及其实战用法,不足之处还望各位大佬指出,一起探讨进步,感谢大家的支持~

今天要讲的是react19的新特性useOptimistic这个新的hooks。

1 useOptimistic简介

这是官方给出的解释:

记得贴图!!!!

image.png optimistic意思是乐观的,这里非常明显,只要一切正常不发生然后问题,提前更新的值就会是期待的那个值,具体我们接着看。

2 问题和业务场景

相信大家开发过程中都遇到过一个问题,比如社交媒体类型的站点里都会有点赞、收藏等交互性极高的操作,我们通常会在点击之后去请求后端的接口,当接口返回后我们再做页面交互,比如点赞+1或者收藏icon的替换等操作在这个过程中如果网络有问题,或者后端反应不及时,那么用户会发现点击之后会发现没有反应,还会怀疑是不是没有点到会再次尝试点击...,那么前端同学们考验你们的时候来了,你的防抖、节流等优化做到位了吗【手动狗头】!

3 useOptimistic来救火

面对以上场景,如果我们使用react19,那么我们可以立即在UI上显示更新(乐观更新),同时后台处理实际API请求

废话不多说上代码:

首先我们定义好一个异步请求的方法likePost(postId, increment),他负责请求后台api接口,这里用定时器mock

// 模拟API请求
const likePost = async (postId, increment) => {
  return new Promise((resolve, reject) => {
    // 模拟网络延迟(1-2秒)
    const delay = Math.random() * 1000 + 1000;
    
    setTimeout(() => {
      // 模拟10%的失败率
      const shouldFail = Math.random() < 0.1;
      
      if (shouldFail) {
        reject(new Error('请求失败,请重试'));
      } else {
        console.log(`成功${increment > 0 ? '点赞' : '取消点赞'}帖子 ${postId}`);
        resolve();
      }
    }, delay);
  });
};

接着是useOptimistic的核心功能:

  • 创建乐观状态 optimisticLikes,它会在用户操作时立即更新
  • 定义更新函数 updateOptimisticLikes,用于修改乐观状态
import { useState, useCallback } from 'react';
import { useOptimistic } from 'react';

const PostItem = ({ post }) => {
  // 使用 useOptimistic 管理点赞状态
  const [optimisticLikes, updateOptimisticLikes] = useOptimistic(
    post.likes,
    (currentLikes, delta) => {
      // 确保点赞数不会低于0
      const newLikes = currentLikes + delta;
      return Math.max(newLikes, 0);
    }
  );

  const [isPending, setIsPending] = useState(false);
  const [error, setError] = useState(null);

  const handleLike = useCallback(async () => {
    setIsPending(true);
    setError(null);
    
    try {
      // 乐观更新:立即增加点赞数
      updateOptimisticLikes(1);
      
      // 发送API请求
      await likePost(post.id, 1);
    } catch (err) {
      // 请求失败:回滚到之前的状态
      updateOptimisticLikes(-1);
      setError(err.message);
    } finally {
      setIsPending(false);
    }
  }, [post.id, updateOptimisticLikes]);

  const handleUnlike = useCallback(async () => {
    if (optimisticLikes <= 0) return;
    
    setIsPending(true);
    setError(null);
    
    try {
      // 乐观更新:立即减少点赞数
      updateOptimisticLikes(-1);
      
      // 发送API请求
      await likePost(post.id, -1);
    } catch (err) {
      // 请求失败:回滚到之前的状态
      updateOptimisticLikes(1);
      setError(err.message);
    } finally {
      setIsPending(false);
    }
  }, [post.id, optimisticLikes, updateOptimisticLikes]);

  return (
    <div className="post">
      <h3>{post.title}</h3>
      <p>{post.content}</p>
      
      <div className="like-section">
        <button 
          onClick={handleLike} 
          disabled={isPending}
          className={isPending ? 'pending' : ''}
        >
          👍 点赞
        </button>
        
        <button 
          onClick={handleUnlike} 
          disabled={isPending || optimisticLikes <= 0}
          className={isPending ? 'pending' : ''}
        >
          👎 取消
        </button>
        
        <div className="likes-count">
          <span>{optimisticLikes}</span>
          <span> 人点赞</span>
        </div>
        
        {error && <div className="error">{error}</div>}
      </div>
    </div>
  );
};

const SocialMediaApp = () => {
  const [posts] = useState([
    { id: 1, title: "React 19 发布啦!", content: "React 19 带来了许多令人兴奋的新特性...", likes: 42 },
    { id: 2, title: "学习 useOptimistic", content: "useOptimistic 是处理乐观更新的绝佳方式...", likes: 18 },
    { id: 3, title: "前端开发趋势", content: "2025年前端开发有哪些新趋势?一起来看看...", likes: 56 }
  ]);

  return (
    <div className="social-media-app">
      <header>
        <h1>社交媒体应用</h1>
        <p>体验 React 19 的 useOptimistic 功能</p>
      </header>
      
      <div className="posts-container">
        {posts.map(post => (
          <PostItem key={post.id} post={post} />
        ))}
      </div>
      
      <div className="explanation">
        <h3>useOptimistic 工作原理:</h3>
        <ol>
          <li>用户点击点赞按钮时,立即更新UI(乐观更新)</li>
          <li>后台发送API请求到服务器</li>
          <li>如果请求成功,状态保持更新</li>
          <li>如果请求失败,自动回滚到之前的状态</li>
        </ol>
        <p>注:此演示模拟了10%的API失败率,体验失败时的自动回滚效果</p>
      </div>
    </div>
  );
};

export default SocialMediaApp;

我们梳理一下点赞的逻辑:

  • 用户点击点赞按钮时,立即调用 updateOptimisticLikes(1)
  • 同时发起异步请求 likePost(post.id, 1)
  • 如果请求成功,状态保持更新,无需修改
  • 如果请求失败(模拟10%失败率),调用 updateOptimisticLikes(-1) 回滚状态

UI的显示逻辑是:

  • 使用 isPending 状态显示加载效果
  • 显示错误信息(当API请求失败时)
  • 禁用按钮防止重复操作

4 与之前版本的区别

// React 18 实现方式
const [likes, setLikes] = useState(post.likes);
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);

const handleLike = async () => {
  setIsPending(true);
  setError(null);
  
  // 保存当前状态以便回滚
  const previousLikes = likes;
  
  // 乐观更新
  setLikes(prev => prev + 1);
  
  try {
    await likePost(post.id, 1);
  } catch (err) {
    // 请求失败,回滚到之前的状态
    setLikes(previousLikes);
    setError(err.message);
  } finally {
    setIsPending(false);
  }
};

这样看,感觉好像18也挺简单的,不过在方法里多了previousLikes的中间状态,但是官方更推荐使用hooks来进行状态的管,主要好处是:

  • 简化状态管理逻辑,无需手动保存之前的状态
  • 更优雅的回滚机制,避免状态不一致问题
  • 更好的性能优化,减少不必要的渲染
  • 代码更简洁,逻辑更清晰

这个演示展示了 useOptimistic 如何显著改善需要即时 UI 反馈的交互体验,特别是在网络请求可能延迟或失败的场景中。