index.js
Overview
This file implements a React functional component named App that demonstrates an optimistic UI pattern using the SWR (Stale-While-Revalidate) library. The component manages a to-do list fetched from a remote API and allows users to add new items optimistically—updating the UI immediately on user input before the server confirms the change.
The core functionality revolves around:
Fetching the full to-do list from
/api/todosusinguseSWR.Allowing users to add new to-dos via a form.
Using
mutatefrom SWR to optimistically update the UI with the new item.Rolling back the UI update if the server mutation fails.
Displaying feedback messages about the mutation status.
Revalidating and synchronizing the cache with the server asynchronously.
This approach provides a responsive user experience by minimizing perceived latency during data mutations.
Detailed Explanation
Imports
import useSWR from 'swr'
import React, { useState } from 'react'
import fetch from '../libs/fetch'
useSWR: React hook for data fetching and caching.useState: React hook for local component state.fetch: Custom fetch utility for API calls.
App Component
export default function App() { ... }
The main React component rendering the to-do list UI and handling data fetching and mutation.
State Variables
text(string): Controlled input state for the new to-do text.data(Array<{id: number, text: string}> | undefined): Cached to-do list fetched from/api/todos.mutate(Function): SWR’s mutation function to update cache and trigger revalidation.state(ReactNode): UI feedback state showing mutation progress or errors.
Data Fetching with SWR
const { data, mutate } = useSWR('/api/todos', fetch)
Fetches the full to-do list from the
/api/todosendpoint.Caches and keeps the data synchronized.
dataisundefinedinitially until the fetch resolves.
Adding a New To-Do Item
The form submission is handled via a button click event (with form submission prevented):
<form onSubmit={ev => ev.preventDefault()}>
<input
value={text}
onChange={e => setText(e.target.value)}
placeholder="Add your to-do here..."
autoFocus
/>
<button
type="submit"
onClick={async () => { ... }}
>
Add
</button>
</form>
Mutation Logic on Add Button Click
When the user clicks "Add":
Reset input and show optimistic state
setText('')
setState(<span className="info">Showing optimistic data, mutating...</span>)
Create a new to-do object
const newTodo = {
id: Date.now(),
text
}
Call
mutatewith optimistic update
await mutate(
fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(newTodo)
}),
{
optimisticData: [...data, newTodo],
rollbackOnError: true,
populateCache: newItem => {
setState(<span className="success">Successfully mutated the resource and populated cache. Revalidating...</span>)
return [...data, newItem]
},
revalidate: true
}
)
optimisticData: Immediately appends the new to-do to the cached list for instant UI update.rollbackOnError: If the POST request fails, SWR rolls back to the previous cache automatically.populateCache: Receives the server response (the new item, with capitalized text) and merges it into the cached list.revalidate: Triggers a background fetch to synchronize cache.
Update status on success or failure
On successful mutation and revalidation:
setState(<span className="info">Revalidated the resource.</span>)
On error:
setState(<span className="error">Failed to mutate. Rolled back to previous state and revalidated the resource.</span>)
Rendering Logic
Title and explanation: A heading and a note explaining the optimistic UI pattern and API behavior.
Input and Add button: For entering new to-do text and triggering mutation.
Status message: Displays mutation state feedback from
state.To-do list rendering
<ul>
{data ? (
data.length ? (
data.map(todo => <li key={todo.id}>{todo.text}</li>)
) : (
<i>No todos yet. Try adding lowercased "banana" and "apple" to the list.</i>
)
) : (
<i>Loading...</i>
)}
</ul>
Shows loading message if data is not yet fetched.
Shows a message when no to-dos exist.
Otherwise, renders the list of to-dos.
Important Implementation Details
Optimistic UI Pattern: Uses SWR’s
mutatewithoptimisticDatato immediately reflect changes in the UI without waiting for the server.Rollback on Error: If the POST request fails, SWR automatically reverts the cache to the prior state, ensuring data consistency.
Cache Population via
populateCache: The server returns only the newly created to-do (with text capitalized). The function merges this item into the existing cache, replacing the optimistic version.Background Revalidation: After mutation, SWR revalidates the cache to ensure consistency with the server’s state.
UI Feedback State: The component maintains a separate local state to indicate the mutation phases (
info,success,errormessages) for better user experience.Unique IDs: Uses
Date.now()as a simple unique ID generator for new items optimistically.No form submission: The form submission event is prevented to avoid page refresh.
Interaction with Other Parts of the System
fetchUtility: Abstracts network requests; used here for both GET and POST requests to/api/todos.API Endpoints:
GET /api/todos: Returns the full list of to-dos.POST /api/todos: Accepts a new to-do, capitalizes its text, adds it, and returns only the newly added item.
SWR Library: Provides data fetching, caching, mutation, and revalidation mechanisms.
Styles and Icons: The component uses CSS classes like
info,success,errorand includes an inline SVG icon for informational notes.Application UI Layer: This component serves as the main UI for the optimistic to-do list feature in the app.
Usage Example
This component can be directly rendered in a React application:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './index'
ReactDOM.render(<App />, document.getElementById('root'))
Visual Diagram: Component Structure and Workflow
flowchart TD
A[User enters to-do text] --> B[Clicks "Add" button]
B --> C[Clear input and show "mutating" state]
C --> D[Call mutate with optimisticData]
D --> E[Update local cache immediately (optimistic)]
E --> F[Render updated to-do list]
D --> G[Send POST request to /api/todos]
G --> H{Response from server}
H -->|Success| I[populateCache merges server item]
I --> J[Update UI with server-confirmed data]
I --> K[Trigger background revalidation]
H -->|Error| L[Rollback cache to previous state]
L --> M[Show error message]
J & M --> F
Summary
The index.js file implements a React component that demonstrates a practical optimistic UI pattern for a to-do list using SWR’s powerful mutate function. It enhances user experience by:
Reflecting user input instantly in the UI.
Handling asynchronous server confirmation.
Providing rollback on failure.
Synchronizing cache with server data through revalidation.
Giving clear feedback on mutation status.
This file is an essential example of how to integrate SWR’s mutation API with React state to build fast, resilient, and user-friendly interfaces.