我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

本文说一下React19的新特性,乐观更新钩子useOptimistic()。这个效果的是使用场景,非常常见。比如:在聊天对话的时候,点击发送按钮,消息会立刻出现在聊天列表里面。或者在发送朋友圈的时候,即使提交的是个视频文件也会立刻出现在时间轴里面,这个就是乐观更新。

苏南大叔:React19新特性,如何理解乐观更新钩子useOptimistic? - 乐观更新useOptimistic
React19新特性,如何理解乐观更新钩子useOptimistic?(图4-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react@19.0.0。乐观更新基于的事实是:绝大多数的情况下,都会更新成功的,更新失败的概率非常小。

一套组合逻辑

乐观更新是一套组合逻辑,并不是单独的useOptimistic()就能够完成的。它只是对数据状态值的一个临时副本修改。在适当的时候,会对副本数据进行对齐修正而已。

官方文档:

函数原型:

const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
  • optimisticState,这个是用于更新界面UI的那个临时数据副本,被“乐观”更新的那个数据就在这里。
  • addOptimistic,这是个用于调用的更新函数,就是启动“乐观”更新的那个函数。它仅仅是个调用,具体的逻辑还是要看updateFn这个函数。
  • state,它就是reactstate状态值。也是optimisticState的原型值,非副本。它一般由useState()来获取提供数据源。(当然也不排除其它的数据源可能性)。
  • updateFn,它是一个具体的函数逻辑。接收参数为:当前state和被更新的数据(addOptimistic传入的第一个参数)。

苏南大叔:React19新特性,如何理解乐观更新钩子useOptimistic? - 流程图
React19新特性,如何理解乐观更新钩子useOptimistic?(图4-2)

optimisticState的真身是stateoptimisticState仅仅是副本。副本更新和真身更新冲突的时候,副本失效。真身更新覆盖副本更新。

官方例子

下面的代码改编自官方范例,效果和各大聊天软件里面的对话框效果很相似。提交按钮就“乐观”更新上去了,用户体验非常好。因为几乎没有延迟。正常逻辑的话,还需要一两秒的数据等待的过程。

import { useOptimistic, useState, useRef } from "react";

function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

async function serverAPI(message) {
  let tmp = getRandomInt(1, 3) * 1000;
  await new Promise((res) => setTimeout(res, tmp));
  return message + "."; // 这个return很重要,被合并到真实state里面,进而影响乐观state
}

function Main({ messages, addRealMessageFn }) {
  const formRef = useRef(null);
  let aaa = useRef(messages.length);

  async function formAction(formData) {
    aaa.current++;
    let message = formData.get("message") + aaa.current.toString();
    addOptimisticMessage(message);
    formRef.current.reset();
    await addRealMessageFn(message);
  }
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) => [
      ...state,
      {
        text: newMessage,
        sending: true,
      },
    ]
  );

  return (
    <>
      <form action={formAction} ref={formRef}>
        <input
          type="text"
          name="message"
          placeholder="你好!"
          defaultValue={"sunan"}
        />
        <button type="submit">发送</button>
      </form>
      {optimisticMessages.map((message, index) => (
        <div key={index}>
          {message.text}
          {!!message.sending && <small>(发送中……)</small>}
        </div>
      ))}
    </>
  );
}

export default function App() {
  const [messages, setMessages] = useState([
    { text: "你好,苏南大叔", sending: false, key: 0 },
    { text: "hola,Uncle Sunan", sending: false, key: 1 },
  ]);
  async function addRealMessageFn(message) {
    const okMessage = await serverAPI(message);
    setMessages((messages) => [...messages, { text: okMessage }]);
  }
  return <Main messages={messages} addRealMessageFn={addRealMessageFn} />;
}

苏南大叔:React19新特性,如何理解乐观更新钩子useOptimistic? - 最终效果
React19新特性,如何理解乐观更新钩子useOptimistic?(图4-3)

存在的问题

目前来说,如果快速连续点击提交按钮的话,会发现提交的结果列表中会有重复数据,并且最终的结果列表是混乱的。待后续文章探讨更新。

苏南大叔:React19新特性,如何理解乐观更新钩子useOptimistic? - 存在的问题
React19新特性,如何理解乐观更新钩子useOptimistic?(图4-4)

相关文章

这个钩子的效果,其实和前面苏南大叔一直写的文章里面的pending效果完全相反。以前的文章是拼命让用户知道这个和服务器端的接口交互过程,pending就是交互。而这个乐观更新,就是尽量不让用户感受到这个数据交互的延迟。延迟客观存在,但是因为大概率情况下,不会出错。所以,就提前把效果展现出来了。这就是乐观更新。

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react