Optimistic store write is never reverted when a router action resolves without changing the data
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 48/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- typescript
- Lĩnh vực
- frontend
Hướng nghiên cứu
Reproduce the issue with the provided Cards example, focusing on createOptimisticStore, the router query, useAction, and the router action's settlement path. Compare the listed throwing, returning, plain async, and nested Solid action variants to identify where the optimistic overlay is left in place. Done means a settled router action restores a0 b1 c2 when the underlying data is unchanged, with the regression covered by a test.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Describe the bug
When a Solid action makes an optimistic write to a store and then calls a router action that resolves without changing the underlying data, the optimistic write is never reverted. The store keeps showing the tentative value indefinitely, even after the query it derives from has refetched the unchanged data; only a page reload shows the truth.
This hits the router's documented validation pattern directly: an action that rejects the mutation by returning new Error("…") leaves the UI showing the change it just rejected. In a kanban board, moving a locked card showed the "is locked" error while the card stayed in its new column.
It happens whatever the router action resolves with (an Error, a plain value, or nothing). It does not happen when:
- the router action throws (the overlay reverts),
- the mutation is a plain async function followed by
revalidate(getCards.key), - the mutation is a nested Solid
actionthat callsrevalidate(getCards.key).
This looks related to #619 (same setup: optimistic store, router query, router action), where the store's value lands but For's index accessors stay stale.
Your Example Website or App
The component below. It needs no server functions: the query and the router action are both client-side.
Steps to Reproduce the Bug or Issue
With @solidjs/[email protected], solid-js/@solidjs/web 2.0.0-rc.9 and @solidjs/[email protected] (client start mode):
import { action as routerAction, createRouter, query, useAction } from "@solidjs/router";
import { action, createMemo, createOptimisticStore, For, Loading } from "solid-js";
type Card = { id: string; order: number };
const db: Card[] = [{ id: "a", order: 0 }, { id: "b", order: 1 }, { id: "c", order: 2 }];
const wait = (ms: number) => new Promise(r => setTimeout(r, ms));
const getCards = query(async () => {
await wait(20);
return db.map(c => ({ ...c }));
}, "cards");
// Rejects the change without touching `db`.
const rejectSwap = routerAction(async () => {
await wait(150);
return new Error("rejected");
}, "reject-swap");
function Cards() {
const data = createMemo(() => getCards());
const [cards, setCards] = createOptimisticStore(() => data(), [] as Card[]);
const sorted = () => [...cards].sort((x, y) => x.order - y.order);
const call = useAction(rejectSwap);
const swap = action(function* () {
setCards(list => {
const [x, y] = [...list].sort((p, q) => p.order - q.order);
const t = x.order;
x.order = y.order;
y.order = t;
});
yield call();
});
return (
<>
<button onClick={() => swap()}>swap</button>
<pre>{sorted().map(c => `${c.id}${c.order}`).join(" ")}</pre>
</>
);
}
const Router = createRouter({ routes: [{ path: "/", component: Cards }] });
export default function App() {
return <Router>{props => <Loading fallback={<p>…</p>}>{props.children}</Loading>}</Router>;
}
- Load the page. It reads
a0 b1 c2. - Click
swap. It immediately readsb0 a1 c2(the optimistic write). - Wait. It still reads
b0 a1 c2indefinitely. Reloading showsa0 b1 c2.
Replacing return new Error("rejected") with return "ok" or with no return gives the same result. Rethrowing the returned error from the generator makes no difference. With a "use server" router action the behavior is the same, in dev and in the production build, and on 2.0.0-next.28.
Expected behavior
The optimistic write reverts when the action settles, leaving a0 b1 c2, as it does when the router action throws or when the mutation is a plain async function or a nested Solid action.
Screenshots or Videos
No response
Platform
- OS: macOS 15 (arm64)
- Browser: Chromium 151 (Playwright headless shell)
- Node: 24.21.0
- Versions:
@solidjs/router2.0.0-next.30 (also 2.0.0-next.28),solid-js/@solidjs/web/@solidjs/signals2.0.0-rc.9,@solidjs/vite-plugin3.0.0-next.44, Vite 8.3.0
Additional context
I have not traced the root cause. The three control variants above use the same query, the same derived createOptimisticStore, and the same unchanged data, so the router action's settle path is the ingredient that leaves the overlay in place.
- Ngôn ngữ chính
- TypeScript
- Star
- 1.3k
- Fork
- 180
- Merge trung bình
- 1 ngày 2 giờ
- Pull request đã merge (30 ngày)
- 26
Chuẩn bị môi trường
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của solidjs/solid-router
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 76/100
solidjs/solid-router#633 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 50/100
solidjs/solid-router#625 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Query enumeration recomputes on pathname/hash-only navigation with unchanged search (Solid 2)Đang mở
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 74/100
solidjs/solid-router#624 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
<A> costs ~6us of server CPU per instance during SSR (20x a plain <a>), mostly mergeProps/splitPropsĐang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 55/100
solidjs/solid-router#583 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
enhancement
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
solidjs/solid-router#569 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của solidjs/solid-router
Issue tương tự
-
needs:triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
Maintainer thường phản hồi trong vòng 1 ngày
-
ai-discovered
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 83/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
jessepollak/home#1627 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
agent-canvas bug llm priority:low ready-for-dev
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
OpenHands/OpenHands#17806 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
radius-project/ai-extensions#923 ·
Maintainer thường phản hồi trong vòng 1 ngày