0
0
RemixHow-ToBeginner ยท 4 min read

How to Use Optimistic UI in Remix for Faster User Feedback

In Remix, use useFetcher to submit data and update the UI immediately before the server responds, enabling an optimistic UI. Update your component state right after submission to reflect changes instantly, then sync with server data when available.
๐Ÿ“

Syntax

Use useFetcher from Remix to handle form submissions without full page reloads. After calling fetcher.submit(), update local state to reflect the expected change immediately (optimistic update). When the server responds, update the state with actual data.

Key parts:

  • useFetcher(): hook to manage fetcher state and submit actions.
  • fetcher.submit(data, { method, action }): sends data to server.
  • Local state: holds optimistic UI changes before server confirmation.
jsx
import { useFetcher } from "@remix-run/react";
import { useState } from "react";

function OptimisticComponent() {
  const fetcher = useFetcher();
  const [items, setItems] = useState([]);

  function addItem(newItem) {
    // Optimistically update UI
    setItems(current => [...current, newItem]);
    // Submit to server
    fetcher.submit({ item: newItem }, { method: "post", action: "/add-item" });
  }

  return null; // UI omitted for brevity
}
๐Ÿ’ป

Example

This example shows a simple list where users add items. The UI updates instantly when adding an item, without waiting for the server. When the server responds, the list syncs with the confirmed data.

jsx
import { useFetcher } from "@remix-run/react";
import { useState, useEffect } from "react";

export default function OptimisticUI() {
  const fetcher = useFetcher();
  const [items, setItems] = useState(["Learn Remix"]);

  // Sync with server response when available
  useEffect(() => {
    if (fetcher.data && fetcher.data.items) {
      setItems(fetcher.data.items);
    }
  }, [fetcher.data]);

  function handleAdd() {
    const newItem = `Item ${items.length + 1}`;
    // Optimistic update
    setItems(current => [...current, newItem]);
    // Submit to server
    fetcher.submit({ item: newItem }, { method: "post", action: "/add-item" });
  }

  return (
    <div>
      <h2>My Items</h2>
      <ul>
        {items.map((item, i) => (
          <li key={i}>{item}</li>
        ))}
      </ul>
      <button onClick={handleAdd} disabled={fetcher.state === "submitting"}>
        Add Item
      </button>
    </div>
  );
}
Output
<div> <h2>My Items</h2> <ul> <li>Learn Remix</li> <li>Item 2</li> <li>Item 3</li> </ul> <button>Add Item</button> </div>
โš ๏ธ

Common Pitfalls

Common mistakes when using optimistic UI in Remix include:

  • Not syncing local state with server response, causing UI to show outdated or incorrect data.
  • Updating UI before submission without rollback on error, leading to inconsistent state.
  • Disabling submit button incorrectly, causing poor user experience.

Always handle server errors and update local state accordingly.

jsx
/* Wrong way: No sync with server response, no error handling */
function addItemWrong(newItem) {
  setItems(current => [...current, newItem]);
  fetcher.submit({ item: newItem }, { method: "post", action: "/add-item" });
  // No effect to update or rollback on error
}

/* Right way: Sync with server and handle errors */
useEffect(() => {
  if (fetcher.data) {
    if (fetcher.data.error) {
      // Rollback optimistic update or show error
      setItems(current => current.slice(0, -1));
      alert(fetcher.data.error);
    } else if (fetcher.data.items) {
      setItems(fetcher.data.items);
    }
  }
}, [fetcher.data]);
๐Ÿ“Š

Quick Reference

  • Use useFetcher to submit data without page reload.
  • Update local state immediately for optimistic UI.
  • Sync local state with server response to confirm or rollback.
  • Handle errors to keep UI consistent.
  • Disable buttons during submission to prevent duplicate requests.
โœ…

Key Takeaways

Use Remix's useFetcher to submit data and update UI instantly for optimistic feedback.
Always sync your local state with server responses to keep data consistent.
Handle server errors to rollback optimistic updates and inform users.
Disable UI controls during submission to avoid duplicate actions.
Optimistic UI improves user experience by making apps feel faster and more responsive.