useOptimistic - This feature is available in the latest Canary

Canary 版本

useOptimistic Hook 目前仅在 React 的 Canary 和实验性渠道中可用。请在此处详细了解 React 的发布渠道

useOptimistic 是一个 React Hook,允许您以乐观的方式更新 UI。

const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);

参考

useOptimistic(state, updateFn)

useOptimistic 是一个 React Hook,允许您在异步操作进行时显示不同的状态。它接受一些状态作为参数,并返回该状态的一个副本,该副本在异步操作(例如网络请求)期间可能不同。您提供一个函数,该函数接受当前状态和操作的输入,并返回在操作挂起时要使用的乐观状态。

此状态称为“乐观”状态,因为它通常用于立即向用户呈现执行操作的结果,即使操作实际上需要时间才能完成。

import { useOptimistic } from 'react';

function AppContainer() {
const [optimisticState, addOptimistic] = useOptimistic(
state,
// updateFn
(currentState, optimisticValue) => {
// merge and return new state
// with optimistic value
}
);
}

请参阅下面的更多示例。

参数

  • state:初始时以及未挂起任何操作时要返回的值。
  • updateFn(currentState, optimisticValue):一个函数,它接受当前状态和传递给 addOptimistic 的乐观值,并返回产生的乐观状态。它必须是一个纯函数。updateFn 接受两个参数。 currentStateoptimisticValue。返回值将是 currentStateoptimisticValue 的合并值。

返回值

  • optimisticState:产生的乐观状态。它等于 state,除非有操作挂起,在这种情况下,它等于 updateFn 返回的值。
  • addOptimisticaddOptimistic 是在进行乐观更新时调用的调度函数。它接受一个任意类型的参数 optimisticValue,并将使用 stateoptimisticValue 调用 updateFn

用法

表单的乐观更新

useOptimistic 钩子提供了一种在后台操作(如网络请求)完成之前乐观更新用户界面的方法。在表单的上下文中,此技术有助于使应用程序感觉响应更快。当用户提交表单时,界面会立即使用预期结果进行更新,而不是等待服务器响应来反映更改。

例如,当用户在表单中键入消息并点击“发送”按钮时,useOptimistic 钩子允许消息立即出现在列表中,并带有“正在发送…”标签,即使消息实际上尚未发送到服务器。这种“乐观”的方法给人以速度快、响应快的印象。然后,表单会尝试在后台真正发送消息。一旦服务器确认消息已收到,“正在发送…”标签就会被移除。

import { useOptimistic, useState, useRef } from "react";
import { deliverMessage } from "./actions.js";

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

  return (
    <>
      {optimisticMessages.map((message, index) => (
        <div key={index}>
          {message.text}
          {!!message.sending && <small> (Sending...)</small>}
        </div>
      ))}
      <form action={formAction} ref={formRef}>
        <input type="text" name="message" placeholder="Hello!" />
        <button type="submit">Send</button>
      </form>
    </>
  );
}

export default function App() {
  const [messages, setMessages] = useState([
    { text: "Hello there!", sending: false, key: 1 }
  ]);
  async function sendMessage(formData) {
    const sentMessage = await deliverMessage(formData.get("message"));
    setMessages((messages) => [...messages, { text: sentMessage }]);
  }
  return <Thread messages={messages} sendMessage={sendMessage} />;
}