Skip to main content

feature(persist): add method getOptions on persist api and update documentation#1075 (GitHub)

PR 37112e5•Base commit: 7e5b72b•Snapshot context: different from repo snapshot (d867e6f)

Heuristic risk: Medium (2 pts)

Rule-based heuristic

This is a rule-based heuristic, not a probability and not a defect prediction. The risk label and the related-file list are separate signals.

tier-a-candidate+2 pts

3 of the 3 related file(s) absent from this PR have Tier A co-change support.

tier-b-candidates+0 pts

Not applicable: at least one Tier A related file is present, which scores instead.

many-source-files+0 pts

1 non-test source file(s) changed, below the threshold of 4.

test-coverage-gap+0 pts

No test gap: every changed source file either has no likely test or has a likely test inside this PR.

import-dependents+0 pts

No changed file has 3 or more direct importers in this PR's import context.

cycle-involvementNot evaluated

not evaluated: import cycles are only known for the pinned repository snapshot and this PR was analyzed at its own base commit.

Changed files (3)

Source files

Msrc/middleware/persist.ts
+2-0
View diff excerpt (21 lines)
diff --git a/src/middleware/persist.ts b/src/middleware/persist.ts
index 3f2008c..d81e629 100644
--- a/src/middleware/persist.ts
+++ b/src/middleware/persist.ts
@@ -85,6 +85,7 @@ interface StorePersist<S extends State, Ps> {
     hasHydrated: () => boolean
     onHydrate: (fn: PersistListener<S>) => () => void
     onFinishHydration: (fn: PersistListener<S>) => () => void
+    getOptions: () => Partial<PersistOptions<S, Ps>>
   }
 }
 
@@ -276,6 +277,7 @@ const persistImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
     clearStorage: () => {
       storage?.removeItem(options.name)
     },
+    getOptions: () => options,
     rehydrate: () => hydrate() as Promise<void>,
     hasHydrated: () => hasHydrated,
     onHydrate: (cb) => {

Test files

Mtests/persistSync.test.tsx
+17-0
View diff excerpt (29 lines)
diff --git a/tests/persistSync.test.tsx b/tests/persistSync.test.tsx
index 3cece94..aebe09e 100644
--- a/tests/persistSync.test.tsx
+++ b/tests/persistSync.test.tsx
@@ -381,6 +381,23 @@ describe('persist middleware with sync configuration', () => {
     )
   })
 
+  it('can access the options through the api', () => {
+    const storage = {
+      getItem: () => null,
+      setItem: jest.fn(),
+      removeItem: () => {},
+    }
+
+    const useStore = create(
+      persist(() => ({ count: 0 }), {
+        name: 'test-storage',
+        getStorage: () => storage,
+      })
+    )
+    expect(useStore.persist.getOptions().name).toBeDefined()
+    expect(useStore.persist.getOptions().name).toBe('test-storage')
+  })
+
   it('can change the options through the api', () => {
     const setItemSpy = jest.fn()
 

Other files

Adocs/persisting-store-data.md
+543-0
View diff excerpt (showing 80 of 550 lines)

Truncated excerpt: showing 80 of 550 lines

diff --git a/docs/persisting-store-data.md b/docs/persisting-store-data.md
new file mode 100644
index 0000000..1ea4b1f
--- /dev/null
+++ b/docs/persisting-store-data.md
@@ -0,0 +1,543 @@
+# Persist middleware
+
+The persist middleware enables you to store your Zustand state in a storage (e.g. `localStorage`, `AsyncStorage`, `IndexedDB`, etc...) thus persisting it's data.
+
+Note that this middleware does support both synchronous storages (e.g. `localStorage`) and asynchronous storages (e.g. `AsyncStorage`), but using an asynchronous storage does come with a cost.
+See [Hydration and asynchronous storages](#Hydration-and-asynchronous-storages) for more details.
+
+Quick example:
+
+```ts
+import create from 'zustand'
+import { persist } from 'zustand/middleware'
+
+export const useStore = create(
+  persist(
+    (set, get) => ({
+      fishes: 0,
+      addAFish: () => set({ fishes: get().fishes + 1 }),
+    }),
+    {
+      name: 'food-storage', // name of item in the storage (must be unique)
+      getStorage: () => sessionStorage, // (optional) by default the 'localStorage' is used
+    }
+  )
+)
+```
+
+See [Options](#Options) for more details.
+
+## Options
+
+### `name`
+
+This is the only required option.
+The given name is going to be the key used to store your Zustand state in the storage, so it must be unique.
+
+### `getStorage`
+
+> Default: `() => localStorage`
+
+Enables you to use your own storage.
+Simply pass a function that returns the storage you want to use.
+
+Example:
+
+```ts
+export const useStore = create(
+  persist(
+    (set, get) => ({
+      // ...
+    }),
+    {
+      // ...
+      getStorage: () => AsyncStorage,
+    }
+  )
+)
+```
+
+The given storage must match the following interface:
+
+```ts
+interface Storage {
+  getItem: (name: string) => string | null | Promise<string | null>
+  setItem: (name: string, value: string) => void | Promise<void>
+  removeItem: (name: string) => void | Promise<void>
+}
+```
+
+### `serialize`
+
+> Schema: `(state: Object) => string | Promise<string>`
+
+> Default: `(state) => JSON.stringify(state)`

Files that historically change together with this PR's changed files in prior commits.

tests/persistAsync.test.tsxTier A (high confidence & support)
Direct import link: no

In history before this PR, 11 of the 16 commits that changed tests/persistSync.test.tsx also changed tests/persistAsync.test.tsx. The other direction: 11 of the 19 commits that changed tests/persistAsync.test.tsx also changed tests/persistSync.test.tsx. No direct import link was found between them at the PR base snapshot. One changed file in this PR points at it.

Related throughtests/persistSync.test.tsx
Co-change support11 shared commits
Directional confidence68.8% forward / 57.9% reverse

Lift 18.16: this file changes together with the changed file far more often than its overall change rate would suggest.

Snapshot code link: This PR was analyzed at its own base commit, not the pinned repository snapshot, so the snapshot code viewer is not available for it.

src/middleware/devtools.tsTier A (high confidence & support)
Direct import link: no

In history before this PR, 6 of the 9 commits that changed src/middleware/persist.ts also changed src/middleware/devtools.ts. The other direction: 6 of the 19 commits that changed src/middleware/devtools.ts also changed src/middleware/persist.ts. No direct import link was found between them at the PR base snapshot. One changed file in this PR points at it.

Related throughsrc/middleware/persist.ts
Co-change support6 shared commits
Directional confidence66.7% forward / 31.6% reverse

Lift 17.61: this file changes together with the changed file far more often than its overall change rate would suggest.

Snapshot code link: This PR was analyzed at its own base commit, not the pinned repository snapshot, so the snapshot code viewer is not available for it.

src/middleware/subscribeWithSelector.tsTier A (high confidence & support)
Direct import link: no

In history before this PR, 5 of the 9 commits that changed src/middleware/persist.ts also changed src/middleware/subscribeWithSelector.ts. The other direction: 5 of the 7 commits that changed src/middleware/subscribeWithSelector.ts also changed src/middleware/persist.ts. No direct import link was found between them at the PR base snapshot. One changed file in this PR points at it.

Related throughsrc/middleware/persist.ts
Co-change support5 shared commits
Directional confidence55.6% forward / 71.4% reverse

Lift 39.84: this file changes together with the changed file far more often than its overall change rate would suggest.

Snapshot code link: This PR was analyzed at its own base commit, not the pinned repository snapshot, so the snapshot code viewer is not available for it.

Standing note: Historical association, not proof that this PR needed to change the file.

Import context (up to two levels)

Anchored on src/middleware/persist.tsDepth 1 • Imported by
  • src/middleware.ts
Anchored on src/middleware/persist.tsDepth 1 • Imports
  • src/vanilla.ts
Anchored on src/middleware/persist.tsDepth 2 • Imported by
  • src/index.ts(via src/vanilla.ts)
  • src/middleware/combine.ts(via src/vanilla.ts)
  • src/middleware/devtools.ts(via src/vanilla.ts)
  • src/middleware/immer.ts(via src/vanilla.ts)
  • src/middleware/redux.ts(via src/vanilla.ts)
  • src/middleware/subscribeWithSelector.ts(via src/vanilla.ts)
  • src/react.ts(via src/vanilla.ts)

Suggested tests (filename heuristic)

The filename heuristic could not identify any matching test files.

Prepared review

Prepared • Stored text from offline analysis, not a live AI response

Diff-grounded observations

src/middleware/persist.ts
“getOptions: () => options”

The persist api gains getOptions(), which returns the current options object held by the middleware.

src/middleware/persist.ts
“getOptions: () => Partial<PersistOptions<S, Ps>>”

The StorePersist interface declares getOptions: () => Partial<PersistOptions<S, Ps>>.

tests/persistSync.test.tsx
“expect(useStore.persist.getOptions().name).toBe('test-storage')”

A new sync-storage test checks that getOptions() reports the configured storage name.

docs/persisting-store-data.md
“The persist middleware enables you to store your Zustand state in a storage”

A new documentation page for the persist middleware was added in the same PR.

Broader context (not about changed lines)

tests/persistAsync.test.tsx is a related file not in this PR: it shares 11 commits with the changed tests/persistSync.test.tsx and no direct import link was found between them.
src/middleware/devtools.ts (6 shared commits) and src/middleware/subscribeWithSelector.ts (5 shared commits) are related files not in this PR, both measured against the changed src/middleware/persist.ts.
This PR was analyzed at its own base commit rather than the pinned repository snapshot, so snapshot-only signals such as import-cycle membership are reported as not evaluated.
The docs diff excerpt is truncated (80 of 550 lines). Candidates are historical co-change partners, not a claim that any file was required in this PR. This review is prepared text over stored excerpts only, not a live model response.