ITADN

Optimistic updates with rollback

#825Closedk2d222 创建于 2025-12-30
K
k2d222commented
### Describe The Problem To Be Solved I'm looking for ways to perform [optimistic updates](https://tanstack.com/query/v4/docs/framework/react/guides/optimistic-updates) in Solid, and I think it could be a useful primitive. --- When a user interacts with a UI element that triggers a server API call (e.g., clicking a like button), there are two ways to handle asynchronicity: 1. The "conservative" way: - send the request and wait/listen to the response, - if server success: mutate the frontend state. - if server failure: display the error message. 2. The "opportunistic" way: - preemptively mutate the frontend state, - send the request and wait/listen to the response, - if server failure: rollback the state and display the error message. Opportunistic updates make frontends snappier by erasing the client-server communication latency. ### Suggest A Solution I've recently been using a small utility to provide signals with async updates and rollback functionality. The short version is below: <details> ```ts function createOptimisticSignal<T>(commitFn: (val: T) => PromiseLike<void>, initialVal: T) { const [committedVal, setCommittedVal] = createSignal<T>(initialVal) const [tempVal, setTempVal] = createSignal<T>(initialVal) const commit = async (v: T) => { setTempVal(v) try { await commitFn(v) setCommittedVal(v) } catch (e) { // rollback if update failed setTempVal(committedVal()) throw e } } createEffect(() => { // reset the temporary value on commit setTempVal(committedVal()) }) return { val: tempVal, commit, committedVal, setCommittedVal, } } ``` </details> in a nutshell, it returns a signal getter and a setter (`val` and `commit`). The commit function must throw or reject if the transaction failed. It also provides means to get and set the committed value manually. A more polished version of this utility would contain error handling and state management, like `createResource()`. Example usage below: <details> ```ts interface Server { setLiked(b: boolean) => Promise<void> // may throw, if the server fails for some reason getLiked() => Promise<boolean> on(event: string, callback: Function) // has events that may affect the 'liked' state } const likeButton = createOptimisticSignal<boolean>(server.setLiked, false) server.on('liked', likeButton.setCommittedVal) // may be triggered if my friend clicks the button… <button on:click={() => likeButton.commit(!likeButton.val())}>{likeButton.val() ? 'Unlike me!' : 'Like me!'}</button> ``` </details>
关闭于 2026-01-05 3 条评论