Skip to content

v0.28.0

Latest

Choose a tag to compare

@ValentinKolb ValentinKolb released this 08 Oct 17:32
· 6 commits to main since this release
4a388b3

What changed

Errors thrown by your components no longer end up in the state of the Solid primitives they read. query.create, query.createInfinite, mutation.create, clipboard.create and clipboard.createWriter now keep their own error() for failures of the work they run (load, mutation, copy). An error thrown by a component or computation that reads their signals goes to the nearest Solid error boundary, or surfaces as an unhandled error.

  • Queries: results are committed in one batch after internal state has settled. loading(), refreshing(), stale() and loadingMore() stay consistent, and invalidate() resolves once its snapshot is committed, even if a reader throws. A reader error while a load, invalidate(), loadMore() or abort() starts no longer leaves a query looking busy without a running load.
  • Mutations: onSuccess now runs after data() and loading() are updated, and onFinally always runs.
  • Clipboard: copy() rejects with reader errors during copy feedback instead of reporting a failed copy, and wasCopied() always resets.

Migration: mutate() contract

mutate() and retry() can now reject. They reject only with errors thrown by onSuccess or by components reading the committed result. These errors no longer set error() and no longer call onError; error() and onError are reserved for failures of the mutation function itself.

If you relied on onError to catch failures inside onSuccess, handle them where the mutation is triggered instead:

try {
  await save.mutate(input);
} catch (err) {
  // onSuccess or a reader of the result threw
}

or wrap the reading component in a Solid <ErrorBoundary>. Calls such as void save.mutate(input) or event handlers that don't await mutate() will now report these errors as unhandled rejections instead of swallowing them.

Full changelog: CHANGELOG.md