From 8c37913865c8712b50b8c2e7caa50bb907a30486 Mon Sep 17 00:00:00 2001 From: David Maskasky Date: Tue, 17 Dec 2024 19:01:38 -0800 Subject: [PATCH 1/3] fix(store): robust flush batch (#2871) * debug batching * process all batch functions even on error * Update src/vanilla/store.ts Co-authored-by: Daishi Kato --------- Co-authored-by: Daishi Kato --- src/vanilla/store.ts | 19 ++++++++----------- tests/vanilla/store.test.tsx | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/vanilla/store.ts b/src/vanilla/store.ts index 73eb9fb06c..341f81a351 100644 --- a/src/vanilla/store.ts +++ b/src/vanilla/store.ts @@ -201,7 +201,7 @@ const registerBatchAtom = ( if (!batch.D.has(atom)) { batch.D.set(atom, new Set()) addBatchFuncMedium(batch, () => { - atomState.m?.l.forEach((listener) => listener()) + atomState.m?.l.forEach((listener) => addBatchFuncMedium(batch, listener)) }) } } @@ -220,12 +220,6 @@ const addBatchAtomDependent = ( const getBatchAtomDependents = (batch: Batch, atom: AnyAtom) => batch.D.get(atom) -const copySetAndClear = (origSet: Set): Set => { - const newSet = new Set(origSet) - origSet.clear() - return newSet -} - const flushBatch = (batch: Batch) => { let error: AnyError let hasError = false @@ -239,11 +233,14 @@ const flushBatch = (batch: Batch) => { } } } - while (batch.M.size || batch.L.size) { + while (batch.H.size || batch.M.size || batch.L.size) { batch.D.clear() - copySetAndClear(batch.H).forEach(call) - copySetAndClear(batch.M).forEach(call) - copySetAndClear(batch.L).forEach(call) + batch.H.forEach(call) + batch.H.clear() + batch.M.forEach(call) + batch.M.clear() + batch.L.forEach(call) + batch.L.clear() } if (hasError) { throw error diff --git a/tests/vanilla/store.test.tsx b/tests/vanilla/store.test.tsx index ea6a97e019..5a186b0a3f 100644 --- a/tests/vanilla/store.test.tsx +++ b/tests/vanilla/store.test.tsx @@ -983,3 +983,25 @@ it('mounted atom should be recomputed eagerly', () => { store.set(a, 1) expect(result).toEqual(['bRead', 'aCallback', 'bCallback']) }) + +it('should process all atom listeners even if some of them throw errors', () => { + const store = createStore() + const a = atom(0) + const listenerA = vi.fn() + const listenerB = vi.fn(() => { + throw new Error('error') + }) + const listenerC = vi.fn() + + store.sub(a, listenerA) + store.sub(a, listenerB) + store.sub(a, listenerC) + try { + store.set(a, 1) + } catch { + // expect empty + } + expect(listenerA).toHaveBeenCalledTimes(1) + expect(listenerB).toHaveBeenCalledTimes(1) + expect(listenerC).toHaveBeenCalledTimes(1) +}) From a9933f1219b2148ee95814d1257bdfb4955196da Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Wed, 18 Dec 2024 12:14:21 +0900 Subject: [PATCH 2/3] docs(*): change 'npm i' to 'npm install' (#2865) * docs(*): change 'npm i' to 'npm install' * Update readme.md Co-authored-by: Daishi Kato --------- Co-authored-by: Daishi Kato --- docs/extensions/cache.mdx | 2 +- docs/extensions/effect.mdx | 2 +- docs/extensions/immer.mdx | 2 +- docs/extensions/location.mdx | 2 +- docs/extensions/optics.mdx | 2 +- docs/extensions/query.mdx | 4 ++-- docs/extensions/redux.mdx | 2 +- docs/extensions/relay.mdx | 2 +- docs/extensions/scope.mdx | 4 ++-- docs/extensions/trpc.mdx | 2 +- docs/extensions/urql.mdx | 2 +- docs/extensions/valtio.mdx | 2 +- docs/extensions/xstate.mdx | 2 +- docs/extensions/zustand.mdx | 2 +- docs/third-party/derive.mdx | 2 +- docs/third-party/history.mdx | 2 +- docs/tools/devtools.mdx | 2 +- website/src/pages/index.js | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/extensions/cache.mdx b/docs/extensions/cache.mdx index 1652bb0e0c..7f2c8b2806 100644 --- a/docs/extensions/cache.mdx +++ b/docs/extensions/cache.mdx @@ -18,7 +18,7 @@ a third-party library to help such use cases. ### Install ``` -npm i jotai-cache +npm install jotai-cache ``` ## atomWithCache diff --git a/docs/extensions/effect.mdx b/docs/extensions/effect.mdx index f37ddae7f3..413d5f6759 100644 --- a/docs/extensions/effect.mdx +++ b/docs/extensions/effect.mdx @@ -10,7 +10,7 @@ keywords: effect, atom effect, side effect, side-effect, sideeffect ## install ``` -npm i jotai-effect +npm install jotai-effect ``` ## atomEffect diff --git a/docs/extensions/immer.mdx b/docs/extensions/immer.mdx index e5fdc56cb8..794d6aa287 100644 --- a/docs/extensions/immer.mdx +++ b/docs/extensions/immer.mdx @@ -10,7 +10,7 @@ keywords: immer You have to install `immer` and `jotai-immer` to use this feature. ``` -npm i immer jotai-immer +npm install immer jotai-immer ``` ## atomWithImmer diff --git a/docs/extensions/location.mdx b/docs/extensions/location.mdx index 62af53a381..39677aa5de 100644 --- a/docs/extensions/location.mdx +++ b/docs/extensions/location.mdx @@ -12,7 +12,7 @@ To deal with `window.location`, we have some functions to create atoms. You have to install `jotai-location` to use this feature. ``` -npm i jotai-location +npm install jotai-location ``` ## atomWithLocation diff --git a/docs/extensions/optics.mdx b/docs/extensions/optics.mdx index 601946159d..4409fc6179 100644 --- a/docs/extensions/optics.mdx +++ b/docs/extensions/optics.mdx @@ -10,7 +10,7 @@ keywords: optics You have to install `optics-ts` and `jotai-optics` to use this feature. ``` -npm i optics-ts jotai-optics +npm install optics-ts jotai-optics ``` ## focusAtom diff --git a/docs/extensions/query.mdx b/docs/extensions/query.mdx index fb1103c818..05026b8ae1 100644 --- a/docs/extensions/query.mdx +++ b/docs/extensions/query.mdx @@ -22,7 +22,7 @@ jotai-tanstack-query currently supports TanStack Query v5. In addition to `jotai`, you have to install `jotai-tanstack-query` and `@tanstack/query-core` to use the extension. ```bash -npm i jotai-tanstack-query @tanstack/query-core +npm install jotai-tanstack-query @tanstack/query-core ``` ### Incremental Adoption @@ -338,7 +338,7 @@ See [a working example](https://codesandbox.io/s/4gfp6z) to learn more. In order to use the Devtools, you need to install it additionally. ```bash -npm i @tanstack/react-query-devtools +npm install @tanstack/react-query-devtools ``` All you have to do is put the `` within ``. diff --git a/docs/extensions/redux.mdx b/docs/extensions/redux.mdx index b6b509300c..4b4999f9ab 100644 --- a/docs/extensions/redux.mdx +++ b/docs/extensions/redux.mdx @@ -17,7 +17,7 @@ and sync with atoms in Jotai. You have to install `redux` and `jotai-redux` to use this feature. ``` -npm i redux jotai-redux +npm install redux jotai-redux ``` ## atomWithStore diff --git a/docs/extensions/relay.mdx b/docs/extensions/relay.mdx index a09c5315c7..d06b9d4955 100644 --- a/docs/extensions/relay.mdx +++ b/docs/extensions/relay.mdx @@ -13,7 +13,7 @@ You can use Jotai with [Relay](https://relay.dev). You have to install `jotai-relay` and `relay-runtime`. ``` -npm i jotai-relay relay-runtime +npm install jotai-relay relay-runtime ``` ### Usage diff --git a/docs/extensions/scope.mdx b/docs/extensions/scope.mdx index 5b9053ed3d..b7249100b9 100644 --- a/docs/extensions/scope.mdx +++ b/docs/extensions/scope.mdx @@ -22,7 +22,7 @@ and the use of those atoms is scoped within the subtree. ### Install ``` -npm i jotai-scope +npm install jotai-scope ``` ### Counter Example @@ -105,7 +105,7 @@ See [Motivation](https://github.com/saasquatch/bunshi/tree/v1.1.1#motivation) fo ### Install ``` -npm i bunshi +npm install bunshi ``` ### Counter Example diff --git a/docs/extensions/trpc.mdx b/docs/extensions/trpc.mdx index 2a41a135f7..603732bff5 100644 --- a/docs/extensions/trpc.mdx +++ b/docs/extensions/trpc.mdx @@ -12,7 +12,7 @@ You can use Jotai with [tRPC](https://trpc.io). You have to install `jotai-trpc`, `@trpc/client` and `@trpc/server` to use the extension. ``` -npm i jotai-trpc @trpc/client @trpc/server +npm install jotai-trpc @trpc/client @trpc/server ``` ### Usage diff --git a/docs/extensions/urql.mdx b/docs/extensions/urql.mdx index d8913a1aaa..3666e46b89 100644 --- a/docs/extensions/urql.mdx +++ b/docs/extensions/urql.mdx @@ -18,7 +18,7 @@ From the [Overview docs](https://formidable.com/open-source/urql/docs/): You have to install `jotai-urql`, `@urql/core` and `wonka` to use the extension. ``` -npm i jotai-urql @urql/core wonka +npm install jotai-urql @urql/core wonka ``` ### Exported functions diff --git a/docs/extensions/valtio.mdx b/docs/extensions/valtio.mdx index c298513b41..8f6284efd6 100644 --- a/docs/extensions/valtio.mdx +++ b/docs/extensions/valtio.mdx @@ -19,7 +19,7 @@ This only uses the vanilla api of valtio. You have to install `valtio` and `jotai-valtio` to use this feature. ``` -npm i valtio jotai-valtio +npm install valtio jotai-valtio ``` ## atomWithProxy diff --git a/docs/extensions/xstate.mdx b/docs/extensions/xstate.mdx index 1701a4934a..fdd8d180bb 100644 --- a/docs/extensions/xstate.mdx +++ b/docs/extensions/xstate.mdx @@ -15,7 +15,7 @@ a better and safer abstraction for state management. You have to install `xstate` and `jotai-xstate` to use this feature. ``` -npm i xstate jotai-xstate +npm install xstate jotai-xstate ``` ## atomWithMachine diff --git a/docs/extensions/zustand.mdx b/docs/extensions/zustand.mdx index 0890ef834b..c4635a1678 100644 --- a/docs/extensions/zustand.mdx +++ b/docs/extensions/zustand.mdx @@ -19,7 +19,7 @@ This only uses the vanilla api of zustand. You have to install `zustand` and `jotai-zustand` to use this feature. ``` -npm i zustand jotai-zustand +npm install zustand jotai-zustand ``` ## atomWithStore diff --git a/docs/third-party/derive.mdx b/docs/third-party/derive.mdx index fa15fbe78b..8eb887e6f1 100644 --- a/docs/third-party/derive.mdx +++ b/docs/third-party/derive.mdx @@ -21,7 +21,7 @@ Building data graphs with these dual-natured (sometimes async, sometimes sync) a You have to install `jotai-derive` to use this feature. ``` -npm i jotai-derive +npm install jotai-derive ``` ## derive diff --git a/docs/third-party/history.mdx b/docs/third-party/history.mdx index ee3f296980..77a0dc857e 100644 --- a/docs/third-party/history.mdx +++ b/docs/third-party/history.mdx @@ -10,7 +10,7 @@ keywords: history,undo,redo,jotai ## install ``` -npm i jotai-history +npm install jotai-history ``` ## withHistory diff --git a/docs/tools/devtools.mdx b/docs/tools/devtools.mdx index 9c9c062385..a96fdbeef5 100644 --- a/docs/tools/devtools.mdx +++ b/docs/tools/devtools.mdx @@ -10,7 +10,7 @@ keywords: devtools,debug,snapshot Install `jotai-devtools` to your project to get started. ```sh -npm i jotai-devtools +npm install jotai-devtools ``` ### Notes diff --git a/website/src/pages/index.js b/website/src/pages/index.js index 6360c8c66f..bc92acfca9 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -118,7 +118,7 @@ const gettingStartedTabs = {

Installation

First add Jotai as a dependency to your React project.

{`# npm -npm i jotai +npm install jotai # yarn yarn add jotai From 7e463d1cf0ccde1cd85039d439d18c2fd7b6f0a9 Mon Sep 17 00:00:00 2001 From: Daishi Kato Date: Thu, 19 Dec 2024 11:54:52 +0900 Subject: [PATCH 3/3] chore(test): dev store method (#2873) --- tests/vanilla/storedev.test.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/vanilla/storedev.test.tsx b/tests/vanilla/storedev.test.tsx index 1771fafc28..15d5418fc0 100644 --- a/tests/vanilla/storedev.test.tsx +++ b/tests/vanilla/storedev.test.tsx @@ -7,7 +7,7 @@ import type { describe('[DEV-ONLY] dev-only methods rev4', () => { it('should get atom value', () => { - const store = createStore() as any + const store = createStore() as INTERNAL_DevStoreRev4 & INTERNAL_PrdStore if (!('dev4_get_internal_weak_map' in store)) { throw new Error('dev methods are not available') } @@ -19,7 +19,7 @@ describe('[DEV-ONLY] dev-only methods rev4', () => { }) it('should restore atoms and its dependencies correctly', () => { - const store = createStore() as any + const store = createStore() as INTERNAL_DevStoreRev4 & INTERNAL_PrdStore if (!('dev4_restore_atoms' in store)) { throw new Error('dev methods are not available') } @@ -32,7 +32,7 @@ describe('[DEV-ONLY] dev-only methods rev4', () => { }) it('should restore atoms and call store listeners correctly', () => { - const store = createStore() as any + const store = createStore() as INTERNAL_DevStoreRev4 & INTERNAL_PrdStore if (!('dev4_restore_atoms' in store)) { throw new Error('dev methods are not available') } @@ -96,4 +96,14 @@ describe('[DEV-ONLY] dev-only methods rev4', () => { const result = store.dev4_get_mounted_atoms() expect(Array.from(result)).toStrictEqual([]) }) + + it('should restore atoms with custom write function', () => { + const store = createStore() as INTERNAL_DevStoreRev4 & INTERNAL_PrdStore + if (!('dev4_restore_atoms' in store)) { + throw new Error('dev methods are not available') + } + const countAtom = atom(0, () => {}) + store.dev4_restore_atoms([[countAtom, 1]]) + expect(store.get(countAtom)).toBe(1) + }) })