useOptimisitc

useOptimistic允许在异步操作进行的时候展示不同的状态,它接受两个参数,一个是用来初始化所要展示的状态,另一个是一个函数,用来在操作挂起期间展示乐观状态使用。

乐观状态 Hook 的常见使用格式如下:

const [optimisticState, addOptimistic] = useOptimistic(
  initialState,
  (currentState, optimisitcValue) => {
    return newState;
  }
);

useOptimistic通常用来立刻向用户展示动作执行结果,即便是这个所需要执行的动作需要一段时间才能够完成。

这里借用官网上的示例来说明useOptimistic要如何来使用。

async function expensiveDeliverMessage(message: string) {
  await new Promise((resolve) => setTimeout(resolve, 3000));
  return message;
}

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

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

const App = () => {
  const [messages, setMessages] = useState([]);
  const sendMessage = async (formData) => {
    const messageSent = await expensiveDeliverMessage(formData.get("message"));
    setMessages((prev) => [...prev, { text: messageSent }]);
  };

  return <Thread messages={messages} sendMessage={sendMessage} />;
};

在这个示例中,组件<Thread>展示的messages内容实际上是从上一级<App>组件中传递来的,而messages的变化也是在<App>中完成的。如果不使用useOptimistic的话,在点击<Thread>组件的提交按钮以后,需要等待一段时间,才能够看到刚刚添加的内容在列表里刷新出来。

但是在<Thread>中使用了useOptimistic以后,<Thread>组件中展示的message列表实际上是经过处理的,在表单提交的时候,<Thread>组件的表单提交处理函数会首先往经过useOptimistic处理后的message列表里添加一条临时的记录。这样看起来就变成了服务已经接受了刚刚输入的内容,但是正在进行处理。此时等到<App>组件中的表单处理完成时,<App>组件传递给<Thread>组件的messages就发生了变化,于是<Thread>组件中展示的列表就被更新以后的messages所替代。

所以从这个示例可以看出,useOptimistic Hook 最大的功用就是优化在应用进行后台操作时,UI 进行提醒和临时信息展示的。善加利用可以让应用的 UI 变得更加友好。