I'm building a collaborative task management app using React 19's useOptimistic hook. Multiple users can update task properties (status, priority, assignee) simultaneously. I'm running into race conditions where optimistic updates overwrite each other, leading to inconsistent UI state.
Environment React 19.0.0 Next.js 15.1.0 Server Actions for mutations
When two rapid updates target the same task but different properties, the second optimistic update replaces the first one entirely instead of merging changes. This causes the UI to briefly show incorrect data until the server response arrives.
here is the code:
'use client'; import { useOptimistic } from 'react'; import { updateTaskStatus, updateTaskPriority } from './actions'; function TaskItem({ task }) { const [optimisticTask, setOptimisticTask] = useOptimistic( task, (state, newTaskData) => ({ ...state, ...newTaskData }) ); const handleStatusChange = async (newStatus) => { setOptimisticTask({ status: newStatus }); await updateTaskStatus(task.id, newStatus); }; const handlePriorityChange = async (newPriority) => { setOptimisticTask({ priority: newPriority }); await updateTaskPriority(task.id, newPriority); }; return ( <div> <h3>{optimisticTask.title}</h3> <select value={optimisticTask.status} onChange={(e) => handleStatusChange(e.target.value)} > <option value="todo">To Do</option> <option value="in-progress">In Progress</option> <option value="done">Done</option> </select> <select value={optimisticTask.priority} onChange={(e) => handlePriorityChange(e.target.value)} > <option value="low">Low</option> <option value="medium">Medium</option> <option value="high">High</option> </select> <p>Status: {optimisticTask.status}</p> <p>Priority: {optimisticTask.priority}</p> </div> ); } Problem: The UI briefly shows status: "todo" (original) because the second optimistic update didn't include status
Question:
What is the recommended pattern for handling multiple concurrent optimistic updates in React 19's use Optimistic hook when updates can arrive out of order and affect overlapping state? Should I implement a pending updates queue with merge logic, or does React 19 provide built-in reconciliation mechanisms I'm not aware of?