DEV Community

Cover image for ReactJS Design Pattern ~Optimistic UI Update~
Ogasawara Kakeru
Ogasawara Kakeru

Posted on

ReactJS Design Pattern ~Optimistic UI Update~

・This pattern enables you to update the UI synchronously with useOptimistic hook while an async operation is pending, such as data fetching. This makes the app feel faster and more responsive by showing alternative UI before the server data is fetched.

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

async function saveTodo(todo) {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  return todo;
}

function App() {
  const [todos, setTodos] = useState(["Learn ReactJs", "Learn NextJs"]);
  const [newTodo, setNewTodo] = useState("");

  const [isPending, startTransition] = useTransition();

  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo) => [...state, newTodo],
  );

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!newTodo.trim()) return;

    startTransition(async () => {
      addOptimisticTodo(newTodo);
      try {
        await saveTodo(newTodo);

        startTransition(() => {
          setTodos((prev) => [...prev, newTodo]);
          setNewTodo("");
        });
      } catch (error) {
        console.error("Failed to save todo");
      }
    });
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          disabled={isPending}
          value={newTodo}
          onChange={(e) => setNewTodo(e.target.value)}
          placeholder="Add a todo"
        />
        <button type="submit">Add</button>
      </form>

      <ul>
        {optimisticTodos.map((todo, index) => (
          <li key={index}>{todo}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Top comments (0)