Merge branch 'main' into v5

This commit is contained in:
daishi 2023-11-14 12:20:18 +09:00
commit abbc74025a
36 changed files with 558 additions and 560 deletions

View File

@ -326,7 +326,7 @@ type State = {
type Actions = {
updateCount: (
countCallback: (count: State['count']) => State['count']
countCallback: (count: State['count']) => State['count'],
) => void
}
@ -362,7 +362,7 @@ type State = {
type Actions = {
updateCount: (
countCallback: (count: State['count']) => State['count']
countCallback: (count: State['count']) => State['count'],
) => void
}

View File

@ -21,7 +21,7 @@ type WithSelectors<S> = S extends { getState: () => infer T }
: never
const createSelectors = <S extends UseBoundStore<StoreApi<object>>>(
_store: S
_store: S,
) => {
let store = _store as WithSelectors<typeof _store>
store.use = {}

View File

@ -38,8 +38,8 @@ export const useBoundStore = create(
{
name: 'food-storage', // unique name
storage: createJSONStorage(() => hashStorage),
}
)
},
),
)
```

View File

@ -135,7 +135,7 @@ import { useStoreWithEqualityFn } from 'zustand/traditional'
function useBearContext<T>(
selector: (state: BearState) => T,
equalityFn?: (left: T, right: T) => boolean
equalityFn?: (left: T, right: T) => boolean,
): T {
const store = useContext(BearContext)
if (!store) throw new Error('Missing BearContext.Provider in the tree')

View File

@ -108,8 +108,8 @@ export const useBoundStore = create(
...createBearSlice(...a),
...createFishSlice(...a),
}),
{ name: 'bound-store' }
)
{ name: 'bound-store' },
),
)
```

View File

@ -249,7 +249,7 @@ export default mergeConfig(
environment: 'jsdom',
setupFiles: ['./setup-vitest.ts'],
},
})
}),
)
```
@ -302,7 +302,7 @@ export const createCounterStore = () => {
}
export const CounterStoreContext = createContext<StoreApi<CounterStore>>(
null as never
null as never,
)
export type CounterStoreProviderProps = PropsWithChildren
@ -322,13 +322,13 @@ export const CounterStoreProvider = ({
export type UseCounterStoreContextSelector<T> = (store: CounterStore) => T
export const useCounterStoreContext = <T,>(
selector: UseCounterStoreContextSelector<T>
selector: UseCounterStoreContextSelector<T>,
): T => {
const counterStoreContext = useContext(CounterStoreContext)
if (counterStoreContext === undefined) {
throw new Error(
'useCounterStoreContext must be used within CounterStoreProvider'
'useCounterStoreContext must be used within CounterStoreProvider',
)
}
@ -371,7 +371,7 @@ describe('Counter', () => {
expect(await screen.findByText(/^1$/)).toBeInTheDocument()
expect(
await screen.findByRole('button', { name: /one up/i })
await screen.findByRole('button', { name: /one up/i }),
).toBeInTheDocument()
})
@ -441,7 +441,7 @@ describe('CounterWithContext', () => {
expect(await screen.findByText(/^1$/)).toBeInTheDocument()
expect(
await screen.findByRole('button', { name: /one up/i })
await screen.findByRole('button', { name: /one up/i }),
).toBeInTheDocument()
})

View File

@ -99,7 +99,7 @@ Imagine you have a scenario like this:
```ts
declare const withError: <T, E>(
p: Promise<T>
p: Promise<T>,
) => Promise<[error: undefined, value: T] | [error: E, value: undefined]>
declare const doSomething: () => Promise<string>
@ -113,10 +113,10 @@ Here, `T` is inferred to be a `string` and `E` is inferred to be `unknown`. You
```ts
declare const withError: {
<E>(): <T>(
p: Promise<T>
p: Promise<T>,
) => Promise<[error: undefined, value: T] | [error: E, value: undefined]>
<T, E>(
p: Promise<T>
p: Promise<T>,
): Promise<[error: undefined, value: T] | [error: E, value: undefined]>
}
declare const doSomething: () => Promise<string>
@ -142,7 +142,7 @@ import { combine } from 'zustand/middleware'
const useBearStore = create(
combine({ bears: 0 }, (set) => ({
increase: (by: number) => set((state) => ({ bears: state.bears + by })),
}))
})),
)
```
@ -181,9 +181,9 @@ const useBearStore = create<BearState>()(
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}),
{ name: 'bearStore' }
)
)
{ name: 'bearStore' },
),
),
)
```
@ -204,7 +204,7 @@ const useBearStore = create<BearState>()(
myMiddlewares((set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}))
})),
)
```
@ -245,12 +245,12 @@ type Logger = <
Mcs extends [StoreMutatorIdentifier, unknown][] = [],
>(
f: StateCreator<T, Mps, Mcs>,
name?: string
name?: string,
) => StateCreator<T, Mps, Mcs>
type LoggerImpl = <T extends State>(
f: StateCreator<T, [], []>,
name?: string
name?: string,
) => StateCreator<T, [], []>
const loggerImpl: LoggerImpl = (f, name) => (set, get, store) => {
@ -274,8 +274,8 @@ const useBearStore = create<BearState>()(
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}),
'bear-store'
)
'bear-store',
),
)
```
@ -298,7 +298,7 @@ type Foo = <
Mcs extends [StoreMutatorIdentifier, unknown][] = [],
>(
f: StateCreator<T, [...Mps, ['foo', A]], Mcs>,
bar: A
bar: A,
) => StateCreator<T, Mps, [['foo', A], ...Mcs]>
declare module 'zustand' {
@ -309,7 +309,7 @@ declare module 'zustand' {
type FooImpl = <T extends State, A>(
f: StateCreator<T, [], []>,
bar: A
bar: A,
) => StateCreator<T, [], []>
const fooImpl: FooImpl = (f, bar) => (set, get, _store) => {
@ -445,11 +445,11 @@ const bearStore = createStore<BearState>()((set) => ({
function useBearStore(): BearState
function useBearStore<T>(
selector: (state: BearState) => T,
equals?: (a: T, b: T) => boolean
equals?: (a: T, b: T) => boolean,
): T
function useBearStore<T>(
selector?: (state: BearState) => T,
equals?: (a: T, b: T) => boolean
equals?: (a: T, b: T) => boolean,
) {
return useStore(bearStore, selector!, equals)
}
@ -473,12 +473,12 @@ const bearStore = createStore<BearState>()((set) => ({
const createBoundedUseStore = ((store) => (selector, equals) =>
useStore(store, selector as never, equals)) as <S extends StoreApi<unknown>>(
store: S
store: S,
) => {
(): ExtractState<S>
<T>(
selector: (state: ExtractState<S>) => T,
equals?: (a: T, b: T) => boolean
equals?: (a: T, b: T) => boolean,
): T
}

View File

@ -47,7 +47,7 @@ export const useCountStore = create<State & Actions>()(
set((state) => {
state.count -= qty
}),
}))
})),
)
```
@ -99,7 +99,7 @@ export const useTodoStore = create<State & Actions>()(
set((state) => {
state.todos[todoId].done = !state.todos[todoId].done
}),
}))
})),
)
```

View File

@ -30,8 +30,8 @@ export const useBearStore = create(
{
name: 'food-storage', // name of the item in the storage (must be unique)
storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used
}
)
},
),
)
```
@ -72,8 +72,8 @@ export const useBoundStore = create(
{
// ...
storage: createJSONStorage(() => AsyncStorage),
}
)
},
),
)
```
@ -98,10 +98,10 @@ export const useBoundStore = create(
// ...
partialize: (state) =>
Object.fromEntries(
Object.entries(state).filter(([key]) => !['foo'].includes(key))
Object.entries(state).filter(([key]) => !['foo'].includes(key)),
),
}
)
},
),
)
```
@ -117,8 +117,8 @@ export const useBoundStore = create(
{
// ...
partialize: (state) => ({ foo: state.foo }),
}
)
},
),
)
```
@ -151,8 +151,8 @@ export const useBoundStore = create(
}
}
},
}
)
},
),
)
```
@ -202,8 +202,8 @@ export const useBoundStore = create(
return persistedState
},
}
)
},
),
)
```
@ -256,8 +256,8 @@ export const useBoundStore = create(
// ...
merge: (persistedState, currentState) =>
deepMerge(currentState, persistedState),
}
)
},
),
)
```
@ -285,8 +285,8 @@ export const useBoundStore = create(
{
// ...
skipHydration: true,
}
)
},
),
)
```
@ -473,7 +473,7 @@ import { useState, useEffect } from 'react'
const useStore = <T, F>(
store: (callback: (state: T) => unknown) => unknown,
callback: (state: T) => F
callback: (state: T) => F,
) => {
const result = store(callback) as F
const [data, setData] = useState<F>()
@ -505,8 +505,8 @@ export const useBearStore = create(
}),
{
name: 'food-storage',
}
)
},
),
)
```
@ -625,8 +625,8 @@ export const useBoundStore = create(
{
name: 'food-storage', // unique name
storage: createJSONStorage(() => storage),
}
)
},
),
)
```
@ -673,8 +673,8 @@ export const useBearStore = create<BearState>()(
{
name: 'food-storage',
storage,
}
)
},
),
)
```
@ -728,8 +728,8 @@ export const useBearStore = create<MyState>()(
name: 'food-storage', // name of item in the storage (must be unique)
storage: createJSONStorage(() => sessionStorage), // (optional) by default the 'localStorage' is used
partialize: (state) => ({ bears: state.bears }),
}
)
},
),
)
```

View File

@ -96,7 +96,8 @@ export default function App({ initialBears }) {
bears: initialBears,
increase: () => set((state) => ({ bears: state.bears + 1 })),
}))
}>
}
>
<Button />
</Provider>
)

View File

@ -180,11 +180,7 @@
},
"prettier": {
"semi": false,
"trailingComma": "es5",
"singleQuote": true,
"bracketSameLine": true,
"tabWidth": 2,
"printWidth": 80
"singleQuote": true
},
"repository": {
"type": "git",

View File

@ -98,12 +98,12 @@ const useBearStore = create((set) => ({
// Object pick, re-renders the component when either state.nuts or state.honey change
const { nuts, honey } = useBearStore(
useShallow((state) => ({ nuts: state.nuts, honey: state.honey }))
useShallow((state) => ({ nuts: state.nuts, honey: state.honey })),
)
// Array pick, re-renders the component when either state.nuts or state.honey change
const [nuts, honey] = useBearStore(
useShallow((state) => [state.nuts, state.honey])
useShallow((state) => [state.nuts, state.honey]),
)
// Mapped picks, re-renders the component when state.treats changes in order, count or keys
@ -115,7 +115,7 @@ For more control over re-rendering, you may provide any custom equality function
```jsx
const treats = useBearStore(
(state) => state.treats,
(oldTreats, newTreats) => compare(oldTreats, newTreats)
(oldTreats, newTreats) => compare(oldTreats, newTreats),
)
```
@ -196,7 +196,7 @@ subscribe(selector, callback, options?: { equalityFn, fireImmediately }): Unsubs
```js
import { subscribeWithSelector } from 'zustand/middleware'
const useDogStore = create(
subscribeWithSelector(() => ({ paw: true, snout: true, fur: true }))
subscribeWithSelector(() => ({ paw: true, snout: true, fur: true })),
)
// Listening to selected changes, in this case when "paw" changes
@ -204,13 +204,13 @@ const unsub2 = useDogStore.subscribe((state) => state.paw, console.log)
// Subscribe also exposes the previous value
const unsub3 = useDogStore.subscribe(
(state) => state.paw,
(paw, previousPaw) => console.log(paw, previousPaw)
(paw, previousPaw) => console.log(paw, previousPaw),
)
// Subscribe also supports an optional equality function
const unsub4 = useDogStore.subscribe(
(state) => [state.paw, state.fur],
console.log,
{ equalityFn: shallow }
{ equalityFn: shallow },
)
// Subscribe and fire immediately
const unsub5 = useDogStore.subscribe((state) => state.paw, console.log, {
@ -272,7 +272,7 @@ const useLushStore = create((set) => ({
set(
produce((state) => {
state.lush.forest.contains = null
})
}),
),
}))
@ -296,14 +296,14 @@ const log = (config) => (set, get, api) =>
console.log(' new state', get())
},
get,
api
api,
)
const useBeeStore = create(
log((set) => ({
bees: false,
setBees: (input) => set({ bees: input }),
}))
})),
)
```
@ -324,8 +324,8 @@ const useFishStore = create(
{
name: 'food-storage', // name of the item in the storage (must be unique)
storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used
}
)
},
),
)
```
@ -346,7 +346,7 @@ const useBeeStore = create(
set((state) => {
state.bees += by
}),
}))
})),
)
```
@ -503,9 +503,9 @@ const useBearStore = create<BearState>()(
}),
{
name: 'bear-storage',
}
)
)
},
),
),
)
```

View File

@ -26,7 +26,7 @@ type UseContextStore<S extends StoreApi<unknown>> = {
(): ExtractState<S>
<U>(
selector: (state: ExtractState<S>) => U,
equalityFn?: (a: U, b: U) => boolean
equalityFn?: (a: U, b: U) => boolean,
): U
}
@ -40,7 +40,7 @@ type WithoutCallSignature<T> = { [K in keyof T]: T[K] }
function createContext<S extends StoreApi<unknown>>() {
if (import.meta.env?.MODE !== 'production') {
console.warn(
"[DEPRECATED] `context` will be removed in a future version. Instead use `import { createStore, useStore } from 'zustand'`. See: https://github.com/pmndrs/zustand/discussions/1180."
"[DEPRECATED] `context` will be removed in a future version. Instead use `import { createStore, useStore } from 'zustand'`. See: https://github.com/pmndrs/zustand/discussions/1180.",
)
}
const ZustandContext = reactCreateContext<S | undefined>(undefined)
@ -61,24 +61,24 @@ function createContext<S extends StoreApi<unknown>>() {
return createElement(
ZustandContext.Provider,
{ value: storeRef.current },
children
children,
)
}
const useContextStore: UseContextStore<S> = <StateSlice = ExtractState<S>>(
selector?: (state: ExtractState<S>) => StateSlice,
equalityFn?: (a: StateSlice, b: StateSlice) => boolean
equalityFn?: (a: StateSlice, b: StateSlice) => boolean,
) => {
const store = useContext(ZustandContext)
if (!store) {
throw new Error(
'Seems like you have not used zustand provider as an ancestor.'
'Seems like you have not used zustand provider as an ancestor.',
)
}
return useStoreWithEqualityFn(
store,
selector as (state: ExtractState<S>) => StateSlice,
equalityFn
equalityFn,
)
}
@ -86,7 +86,7 @@ function createContext<S extends StoreApi<unknown>>() {
const store = useContext(ZustandContext)
if (!store) {
throw new Error(
'Seems like you have not used zustand provider as an ancestor.'
'Seems like you have not used zustand provider as an ancestor.',
)
}
return useMemo<WithoutCallSignature<S>>(() => ({ ...store }), [store])

View File

@ -9,7 +9,7 @@ type Combine = <
Mcs extends [StoreMutatorIdentifier, unknown][] = [],
>(
initialState: T,
additionalStateCreator: StateCreator<T, Mps, Mcs, U>
additionalStateCreator: StateCreator<T, Mps, Mcs, U>,
) => StateCreator<Write<T, U>, Mps, Mcs>
export const combine: Combine =

View File

@ -72,7 +72,7 @@ type Devtools = <
Mcs extends [StoreMutatorIdentifier, unknown][] = [],
>(
initializer: StateCreator<T, [...Mps, ['zustand/devtools', never]], Mcs>,
devtoolsOptions?: DevtoolsOptions
devtoolsOptions?: DevtoolsOptions,
) => StateCreator<T, Mps, [['zustand/devtools', never], ...Mcs]>
declare module '../vanilla' {
@ -84,7 +84,7 @@ declare module '../vanilla' {
type DevtoolsImpl = <T>(
storeInitializer: StateCreator<T, [], []>,
devtoolsOptions?: DevtoolsOptions
devtoolsOptions?: DevtoolsOptions,
) => StateCreator<T, [], []>
export type NamedSet<T> = WithDevtools<StoreApi<T>>['setState']
@ -102,12 +102,12 @@ type ConnectionInformation = {
const trackedConnections: Map<ConnectionName, ConnectionInformation> = new Map()
const getTrackedConnectionState = (
name: string | undefined
name: string | undefined,
): Record<string, any> => {
const api = trackedConnections.get(name)
if (!api) return {}
return Object.fromEntries(
Object.entries(api.stores).map(([key, api]) => [key, api.getState()])
Object.entries(api.stores).map(([key, api]) => [key, api.getState()]),
)
}
@ -116,7 +116,7 @@ const extractConnectionInformation = (
extensionConnector: NonNullable<
(typeof window)['__REDUX_DEVTOOLS_EXTENSION__']
>,
options: Omit<DevtoolsOptions, 'enabled' | 'anonymousActionType' | 'store'>
options: Omit<DevtoolsOptions, 'enabled' | 'anonymousActionType' | 'store'>,
) => {
if (store === undefined) {
return {
@ -160,7 +160,7 @@ const devtoolsImpl: DevtoolsImpl =
if (!extensionConnector) {
if (import.meta.env?.MODE !== 'production' && enabled) {
console.warn(
'[zustand devtools middleware] Please install/enable Redux devtools extension'
'[zustand devtools middleware] Please install/enable Redux devtools extension',
)
}
return fn(set, get, api)
@ -191,7 +191,7 @@ const devtoolsImpl: DevtoolsImpl =
{
...getTrackedConnectionState(options.name),
[store]: api.getState(),
}
},
)
return r
}
@ -215,8 +215,8 @@ const devtoolsImpl: DevtoolsImpl =
key === connectionInformation.store
? initialState
: store.getState(),
])
)
]),
),
)
}
@ -234,7 +234,7 @@ const devtoolsImpl: DevtoolsImpl =
) {
console.warn(
'[zustand devtools middleware] "__setState" action type is reserved ' +
'to set state from the devtools. Avoid using it.'
'to set state from the devtools. Avoid using it.',
)
didWarnAboutReservedActionType = true
}
@ -246,7 +246,7 @@ const devtoolsImpl: DevtoolsImpl =
connection as unknown as {
// FIXME https://github.com/reduxjs/redux-devtools/issues/1097
subscribe: (
listener: (message: Message) => void
listener: (message: Message) => void,
) => (() => void) | undefined
}
).subscribe((message: any) => {
@ -254,7 +254,7 @@ const devtoolsImpl: DevtoolsImpl =
case 'ACTION':
if (typeof message.payload !== 'string') {
console.error(
'[zustand devtools middleware] Unsupported action format'
'[zustand devtools middleware] Unsupported action format',
)
return
}
@ -272,7 +272,7 @@ const devtoolsImpl: DevtoolsImpl =
[zustand devtools middleware] Unsupported __setState action format.
When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),
and value of this only key should be a state object. Example: { "type": "__setState", "state": { "abc123Store": { "foo": "bar" } } }
`
`,
)
}
const stateFromDevtools = (action.state as S)[store]
@ -294,7 +294,7 @@ const devtoolsImpl: DevtoolsImpl =
if (!(api as any).dispatchFromDevtools) return
if (typeof (api as any).dispatch !== 'function') return
;(api as any).dispatch(action)
}
},
)
case 'DISPATCH':
@ -351,7 +351,7 @@ const devtoolsImpl: DevtoolsImpl =
}
connection?.send(
null as any, // FIXME no-any
nextLiftedState
nextLiftedState,
)
return
}
@ -374,7 +374,7 @@ const parseJsonThen = <T>(stringified: string, f: (parsed: T) => void) => {
} catch (e) {
console.error(
'[zustand devtools middleware] Could not parse the received json',
e
e,
)
}
if (parsed !== undefined) f(parsed as T)

View File

@ -7,7 +7,7 @@ type Immer = <
Mps extends [StoreMutatorIdentifier, unknown][] = [],
Mcs extends [StoreMutatorIdentifier, unknown][] = [],
>(
initializer: StateCreator<T, [...Mps, ['zustand/immer', never]], Mcs>
initializer: StateCreator<T, [...Mps, ['zustand/immer', never]], Mcs>,
) => StateCreator<T, Mps, [['zustand/immer', never], ...Mcs]>
declare module '../vanilla' {
@ -50,7 +50,7 @@ type StoreImmer<S> = S extends {
: never
type ImmerImpl = <T>(
storeInitializer: StateCreator<T, [], []>
storeInitializer: StateCreator<T, [], []>,
) => StateCreator<T, [], []>
const immerImpl: ImmerImpl = (initializer) => (set, get, store) => {

View File

@ -17,7 +17,7 @@ export type StorageValue<S> = {
export interface PersistStorage<S> {
getItem: (
name: string
name: string,
) => StorageValue<S> | null | Promise<StorageValue<S> | null>
setItem: (name: string, value: StorageValue<S>) => void | Promise<void>
removeItem: (name: string) => void | Promise<void>
@ -30,7 +30,7 @@ type JsonStorageOptions = {
export function createJSONStorage<S>(
getStorage: () => StateStorage,
options?: JsonStorageOptions
options?: JsonStorageOptions,
): PersistStorage<S> | undefined {
let storage: StateStorage | undefined
try {
@ -56,7 +56,7 @@ export function createJSONStorage<S>(
setItem: (name, newValue) =>
(storage as StateStorage).setItem(
name,
JSON.stringify(newValue, options?.replacer)
JSON.stringify(newValue, options?.replacer),
),
removeItem: (name) => (storage as StateStorage).removeItem(name),
}
@ -92,7 +92,7 @@ export interface PersistOptions<S, PersistedState = S> {
* @default JSON.parse
*/
deserialize?: (
str: string
str: string,
) => StorageValue<PersistedState> | Promise<StorageValue<PersistedState>>
/**
* Use a custom persist storage.
@ -115,7 +115,7 @@ export interface PersistOptions<S, PersistedState = S> {
* The returned function will be called after the state rehydration or when an error occurred.
*/
onRehydrateStorage?: (
state: S
state: S,
) => ((state?: S, error?: unknown) => void) | void
/**
* If the stored state's version mismatch the one specified here, the storage will not be used.
@ -160,16 +160,16 @@ type StorePersist<S, Ps> = {
type Thenable<Value> = {
then<V>(
onFulfilled: (value: Value) => V | Promise<V> | Thenable<V>
onFulfilled: (value: Value) => V | Promise<V> | Thenable<V>,
): Thenable<V>
catch<V>(
onRejected: (reason: Error) => V | Promise<V> | Thenable<V>
onRejected: (reason: Error) => V | Promise<V> | Thenable<V>,
): Thenable<V>
}
const toThenable =
<Result, Input>(
fn: (input: Input) => Result | Promise<Result> | Thenable<Result>
fn: (input: Input) => Result | Promise<Result> | Thenable<Result>,
) =>
(input: Input): Thenable<Result> => {
try {
@ -227,12 +227,12 @@ const oldImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
return config(
(...args) => {
console.warn(
`[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`
`[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`,
)
set(...args)
},
get,
api
api,
)
}
@ -244,7 +244,7 @@ const oldImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
let errorInSync: Error | undefined
const thenable = thenableSerialize({ state, version: options.version })
.then((serializedValue) =>
(storage as StateStorage).setItem(options.name, serializedValue)
(storage as StateStorage).setItem(options.name, serializedValue),
)
.catch((e) => {
errorInSync = e
@ -268,7 +268,7 @@ const oldImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
void setItem()
},
get,
api
api,
)
// a workaround to solve the issue of not storing rehydrated state in sync storage
@ -302,11 +302,11 @@ const oldImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
if (options.migrate) {
return options.migrate(
deserializedStorageValue.state,
deserializedStorageValue.version
deserializedStorageValue.version,
)
}
console.error(
`State loaded from storage couldn't be migrated since no migrate function was provided`
`State loaded from storage couldn't be migrated since no migrate function was provided`,
)
} else {
return deserializedStorageValue.state
@ -316,7 +316,7 @@ const oldImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
.then((migratedState) => {
stateFromStorage = options.merge(
migratedState as S,
get() ?? configResult
get() ?? configResult,
)
set(stateFromStorage as S, true)
@ -392,12 +392,12 @@ const newImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
return config(
(...args) => {
console.warn(
`[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`
`[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`,
)
set(...args)
},
get,
api
api,
)
}
@ -422,7 +422,7 @@ const newImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
void setItem()
},
get,
api
api,
)
// a workaround to solve the issue of not storing rehydrated state in sync storage
@ -456,11 +456,11 @@ const newImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
if (options.migrate) {
return options.migrate(
deserializedStorageValue.state,
deserializedStorageValue.version
deserializedStorageValue.version,
)
}
console.error(
`State loaded from storage couldn't be migrated since no migrate function was provided`
`State loaded from storage couldn't be migrated since no migrate function was provided`,
)
} else {
return deserializedStorageValue.state
@ -470,7 +470,7 @@ const newImpl: PersistImpl = (config, baseOptions) => (set, get, api) => {
.then((migratedState) => {
stateFromStorage = options.merge(
migratedState as S,
get() ?? configResult
get() ?? configResult,
)
set(stateFromStorage as S, true)
@ -546,7 +546,7 @@ const persistImpl: PersistImpl = (config, baseOptions) => {
) {
if (import.meta.env?.MODE !== 'production') {
console.warn(
'[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.'
'[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead.',
)
}
return oldImpl(config, baseOptions)
@ -561,7 +561,7 @@ type Persist = <
U = T,
>(
initializer: StateCreator<T, [...Mps, ['zustand/persist', unknown]], Mcs>,
options: PersistOptions<T, U>
options: PersistOptions<T, U>,
) => StateCreator<T, Mps, [['zustand/persist', U], ...Mcs]>
declare module '../vanilla' {
@ -578,7 +578,7 @@ type WithPersist<S, A> = S extends { getState: () => infer T }
type PersistImpl = <T>(
storeInitializer: StateCreator<T, [], []>,
options: PersistOptions<T, T>
options: PersistOptions<T, T>,
) => StateCreator<T, [], []>
export const persist = persistImpl as unknown as Persist

View File

@ -22,7 +22,7 @@ type Redux = <
Cms extends [StoreMutatorIdentifier, unknown][] = [],
>(
reducer: (state: T, action: A) => T,
initialState: T
initialState: T,
) => StateCreator<Write<T, ReduxState<A>>, Cms, [['zustand/redux', A]]>
declare module '../vanilla' {
@ -33,7 +33,7 @@ declare module '../vanilla' {
type ReduxImpl = <T, A extends Action>(
reducer: (state: T, action: A) => T,
initialState: T
initialState: T,
) => StateCreator<T & ReduxState<A>, [], []>
const reduxImpl: ReduxImpl = (reducer, initial) => (set, _get, api) => {

View File

@ -9,7 +9,7 @@ type SubscribeWithSelector = <
T,
[...Mps, ['zustand/subscribeWithSelector', never]],
Mcs
>
>,
) => StateCreator<T, Mps, [['zustand/subscribeWithSelector', never], ...Mcs]>
type Write<T, U> = Omit<T, keyof U> & U
@ -34,13 +34,13 @@ type StoreSubscribeWithSelector<T> = {
options?: {
equalityFn?: (a: U, b: U) => boolean
fireImmediately?: boolean
}
},
): () => void
}
}
type SubscribeWithSelectorImpl = <T extends object>(
storeInitializer: StateCreator<T, [], []>
storeInitializer: StateCreator<T, [], []>,
) => StateCreator<T, [], []>
const subscribeWithSelectorImpl: SubscribeWithSelectorImpl =

View File

@ -29,12 +29,12 @@ type WithReact<S extends ReadonlyStoreApi<unknown>> = S & {
let didWarnAboutEqualityFn = false
export function useStore<S extends WithReact<StoreApi<unknown>>>(
api: S
api: S,
): ExtractState<S>
export function useStore<S extends WithReact<StoreApi<unknown>>, U>(
api: S,
selector: (state: ExtractState<S>) => U
selector: (state: ExtractState<S>) => U,
): U
/**
@ -44,13 +44,13 @@ export function useStore<S extends WithReact<StoreApi<unknown>>, U>(
export function useStore<S extends WithReact<StoreApi<unknown>>, U>(
api: S,
selector: (state: ExtractState<S>) => U,
equalityFn: ((a: U, b: U) => boolean) | undefined
equalityFn: ((a: U, b: U) => boolean) | undefined,
): U
export function useStore<TState, StateSlice>(
api: WithReact<StoreApi<TState>>,
selector: (state: TState) => StateSlice = api.getState as any,
equalityFn?: (a: StateSlice, b: StateSlice) => boolean
equalityFn?: (a: StateSlice, b: StateSlice) => boolean,
) {
if (
import.meta.env?.MODE !== 'production' &&
@ -58,7 +58,7 @@ export function useStore<TState, StateSlice>(
!didWarnAboutEqualityFn
) {
console.warn(
"[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"
"[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937",
)
didWarnAboutEqualityFn = true
}
@ -67,7 +67,7 @@ export function useStore<TState, StateSlice>(
api.getState,
api.getServerState || api.getState,
selector,
equalityFn
equalityFn,
)
useDebugValue(slice)
return slice
@ -81,16 +81,16 @@ export type UseBoundStore<S extends WithReact<ReadonlyStoreApi<unknown>>> = {
*/
<U>(
selector: (state: ExtractState<S>) => U,
equalityFn: (a: U, b: U) => boolean
equalityFn: (a: U, b: U) => boolean,
): U
} & S
type Create = {
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
initializer: StateCreator<T, [], Mos>
initializer: StateCreator<T, [], Mos>,
): UseBoundStore<Mutate<StoreApi<T>, Mos>>
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(
initializer: StateCreator<T, [], Mos>
initializer: StateCreator<T, [], Mos>,
) => UseBoundStore<Mutate<StoreApi<T>, Mos>>
/**
* @deprecated Use `useStore` hook to bind store
@ -104,7 +104,7 @@ const createImpl = <T>(createState: StateCreator<T, [], []>) => {
typeof createState !== 'function'
) {
console.warn(
"[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`."
"[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.",
)
}
const api =
@ -127,7 +127,7 @@ export const create = (<T>(createState: StateCreator<T, [], []> | undefined) =>
export default ((createState: any) => {
if (import.meta.env?.MODE !== 'production') {
console.warn(
"[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`."
"[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`.",
)
}
return create(createState)

View File

@ -10,7 +10,7 @@ import { shallow } from './vanilla/shallow.ts'
export default ((objA, objB) => {
if (import.meta.env?.MODE !== 'production') {
console.warn(
"[DEPRECATED] Default export is deprecated. Instead use `import { shallow } from 'zustand/shallow'`."
"[DEPRECATED] Default export is deprecated. Instead use `import { shallow } from 'zustand/shallow'`.",
)
}
return shallow(objA, objB)

View File

@ -27,7 +27,7 @@ type WithReact<S extends ReadonlyStoreApi<unknown>> = S & {
}
export function useStoreWithEqualityFn<S extends WithReact<StoreApi<unknown>>>(
api: S
api: S,
): ExtractState<S>
export function useStoreWithEqualityFn<
@ -36,20 +36,20 @@ export function useStoreWithEqualityFn<
>(
api: S,
selector: (state: ExtractState<S>) => U,
equalityFn?: (a: U, b: U) => boolean
equalityFn?: (a: U, b: U) => boolean,
): U
export function useStoreWithEqualityFn<TState, StateSlice>(
api: WithReact<StoreApi<TState>>,
selector: (state: TState) => StateSlice = api.getState as any,
equalityFn?: (a: StateSlice, b: StateSlice) => boolean
equalityFn?: (a: StateSlice, b: StateSlice) => boolean,
) {
const slice = useSyncExternalStoreWithSelector(
api.subscribe,
api.getState,
api.getServerState || api.getState,
selector,
equalityFn
equalityFn,
)
useDebugValue(slice)
return slice
@ -61,30 +61,30 @@ export type UseBoundStoreWithEqualityFn<
(): ExtractState<S>
<U>(
selector: (state: ExtractState<S>) => U,
equalityFn?: (a: U, b: U) => boolean
equalityFn?: (a: U, b: U) => boolean,
): U
} & S
type CreateWithEqualityFn = {
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
initializer: StateCreator<T, [], Mos>,
defaultEqualityFn?: <U>(a: U, b: U) => boolean
defaultEqualityFn?: <U>(a: U, b: U) => boolean,
): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(
initializer: StateCreator<T, [], Mos>,
defaultEqualityFn?: <U>(a: U, b: U) => boolean
defaultEqualityFn?: <U>(a: U, b: U) => boolean,
) => UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>
}
const createWithEqualityFnImpl = <T>(
createState: StateCreator<T, [], []>,
defaultEqualityFn?: <U>(a: U, b: U) => boolean
defaultEqualityFn?: <U>(a: U, b: U) => boolean,
) => {
const api = createStore(createState)
const useBoundStoreWithEqualityFn: any = (
selector?: any,
equalityFn = defaultEqualityFn
equalityFn = defaultEqualityFn,
) => useStoreWithEqualityFn(api, selector, equalityFn)
Object.assign(useBoundStoreWithEqualityFn, api)
@ -94,7 +94,7 @@ const createWithEqualityFnImpl = <T>(
export const createWithEqualityFn = (<T>(
createState: StateCreator<T, [], []> | undefined,
defaultEqualityFn?: <U>(a: U, b: U) => boolean
defaultEqualityFn?: <U>(a: U, b: U) => boolean,
) =>
createState
? createWithEqualityFnImpl(createState, defaultEqualityFn)

View File

@ -1,7 +1,7 @@
type SetStateInternal<T> = {
_(
partial: T | Partial<T> | { _(state: T): T | Partial<T> }['_'],
replace?: boolean | undefined
replace?: boolean | undefined,
): void
}['_']
@ -33,7 +33,7 @@ export type StateCreator<
> = ((
setState: Get<Mutate<StoreApi<T>, Mis>, 'setState', never>,
getState: Get<Mutate<StoreApi<T>, Mis>, 'getState', never>,
store: Mutate<StoreApi<T>, Mis>
store: Mutate<StoreApi<T>, Mis>,
) => U) & { $$storeMutators?: Mos }
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-interface
@ -42,11 +42,11 @@ export type StoreMutatorIdentifier = keyof StoreMutators<unknown, unknown>
type CreateStore = {
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
initializer: StateCreator<T, [], Mos>
initializer: StateCreator<T, [], Mos>,
): Mutate<StoreApi<T>, Mos>
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(
initializer: StateCreator<T, [], Mos>
initializer: StateCreator<T, [], Mos>,
) => Mutate<StoreApi<T>, Mos>
}
@ -54,7 +54,7 @@ type CreateStoreImpl = <
T,
Mos extends [StoreMutatorIdentifier, unknown][] = [],
>(
initializer: StateCreator<T, [], Mos>
initializer: StateCreator<T, [], Mos>,
) => Mutate<StoreApi<T>, Mos>
const createStoreImpl: CreateStoreImpl = (createState) => {
@ -91,7 +91,7 @@ const createStoreImpl: CreateStoreImpl = (createState) => {
const destroy: StoreApi<TState>['destroy'] = () => {
if (import.meta.env?.MODE !== 'production') {
console.warn(
'[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected.'
'[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected.',
)
}
listeners.clear()
@ -111,7 +111,7 @@ export const createStore = ((createState) =>
export default ((createState) => {
if (import.meta.env?.MODE !== 'production') {
console.warn(
"[DEPRECATED] Default export is deprecated. Instead use import { createStore } from 'zustand/vanilla'."
"[DEPRECATED] Default export is deprecated. Instead use import { createStore } from 'zustand/vanilla'.",
)
}
return createStore(createState)
@ -165,7 +165,7 @@ export type Subscribe<T extends State> = {
export type SetState<T extends State> = {
_(
partial: T | Partial<T> | { _(state: T): T | Partial<T> }['_'],
replace?: boolean | undefined
replace?: boolean | undefined,
): void
}['_']

View File

@ -61,7 +61,7 @@ it('uses the store with no args', async () => {
const { findByText } = render(
<>
<Counter />
</>
</>,
)
await findByText('count: 1')
@ -83,7 +83,7 @@ it('uses the store with selectors', async () => {
const { findByText } = render(
<>
<Counter />
</>
</>,
)
await findByText('count: 1')
@ -92,7 +92,7 @@ it('uses the store with selectors', async () => {
it('uses the store with a selector and equality checker', async () => {
const useBoundStore = createWithEqualityFn(
() => ({ item: { value: 0 } }),
Object.is
Object.is,
)
const { setState } = useBoundStore
let renderCount = 0
@ -101,7 +101,7 @@ it('uses the store with a selector and equality checker', async () => {
// Prevent re-render if new value === 1.
const item = useBoundStore(
(s) => s.item,
(_, newItem) => newItem.value === 1
(_, newItem) => newItem.value === 1,
)
return (
<div>
@ -113,7 +113,7 @@ it('uses the store with a selector and equality checker', async () => {
const { findByText } = render(
<>
<Component />
</>
</>,
)
await findByText('renderCount: 1, value: 0')
@ -151,7 +151,7 @@ it('only re-renders if selected state has changed', async () => {
<>
<Counter />
<Control />
</>
</>,
)
fireEvent.click(getByText('button'))
@ -182,7 +182,7 @@ it('can batch updates', async () => {
const { findByText } = render(
<>
<Counter />
</>
</>,
)
await findByText('count: 2')
@ -203,14 +203,14 @@ it('can update the selector', async () => {
const { findByText, rerender } = render(
<StrictMode>
<Component selector={(s) => s.one} />
</StrictMode>
</StrictMode>,
)
await findByText('one')
rerender(
<StrictMode>
<Component selector={(s) => s.two} />
</StrictMode>
</StrictMode>,
)
await findByText('two')
})
@ -220,7 +220,7 @@ it('can update the equality checker', async () => {
type Props = { equalityFn: (a: State, b: State) => boolean }
const useBoundStore = createWithEqualityFn<State>(
() => ({ value: 0 }),
Object.is
Object.is,
)
const { setState } = useBoundStore
const selector = (s: State) => s
@ -239,7 +239,7 @@ it('can update the equality checker', async () => {
const { findByText, rerender } = render(
<>
<Component equalityFn={() => false} />
</>
</>,
)
// This will cause a re-render due to the equality checker.
@ -250,7 +250,7 @@ it('can update the equality checker', async () => {
rerender(
<>
<Component equalityFn={() => true} />
</>
</>,
)
// This will NOT cause a re-render due to the equality checker.
@ -267,7 +267,7 @@ it('can call useBoundStore with progressively more arguments', async () => {
const useBoundStore = createWithEqualityFn<State>(
() => ({ value: 0 }),
Object.is
Object.is,
)
const { setState } = useBoundStore
@ -285,7 +285,7 @@ it('can call useBoundStore with progressively more arguments', async () => {
const { findByText, rerender } = render(
<>
<Component />
</>
</>,
)
await findByText('renderCount: 1, value: {"value":0}')
@ -293,7 +293,7 @@ it('can call useBoundStore with progressively more arguments', async () => {
rerender(
<>
<Component selector={(s) => s.value} />
</>
</>,
)
await findByText('renderCount: 2, value: 0')
@ -304,7 +304,7 @@ it('can call useBoundStore with progressively more arguments', async () => {
selector={(s) => s.value}
equalityFn={(oldV, newV) => oldV > newV}
/>
</>
</>,
)
// Should not cause a re-render because new value is less than previous.
@ -352,7 +352,7 @@ it('can throw an error in selector', async () => {
<ErrorBoundary>
<Component />
</ErrorBoundary>
</StrictMode>
</StrictMode>,
)
await findByText('no error')
@ -400,7 +400,7 @@ it('can throw an error in equality checker', async () => {
<ErrorBoundary>
<Component />
</ErrorBoundary>
</StrictMode>
</StrictMode>,
)
await findByText('no error')
@ -464,7 +464,7 @@ it('can set the store without merging', () => {
const { setState, getState } = create<{ a: number } | { b: number }>(
(_set) => ({
a: 1,
})
}),
)
// Should override the state instead of merging.
@ -512,7 +512,7 @@ it('only calls selectors when necessary', async () => {
const { rerender, findByText } = render(
<>
<Component />
</>
</>,
)
await findByText('inline: 1')
await findByText('static: 1')
@ -520,7 +520,7 @@ it('only calls selectors when necessary', async () => {
rerender(
<>
<Component />
</>
</>,
)
await findByText('inline: 2')
await findByText('static: 1')
@ -571,7 +571,7 @@ it('ensures parent components subscribe before children', async () => {
const { getByText, findByText } = render(
<StrictMode>
<Parent />
</StrictMode>
</StrictMode>,
)
fireEvent.click(getByText('change state'))
@ -614,7 +614,7 @@ it('ensures the correct subscriber is removed on unmount', async () => {
const { findAllByText } = render(
<>
<Component />
</>
</>,
)
expect((await findAllByText('count: 1')).length).toBe(2)
@ -643,14 +643,14 @@ it('ensures a subscriber is not mistakenly overwritten', async () => {
const { findAllByText, rerender } = render(
<StrictMode>
<Count1 />
</StrictMode>
</StrictMode>,
)
// Replace 1st subscriber with another.
rerender(
<StrictMode>
<Count2 />
</StrictMode>
</StrictMode>,
)
// Add 2 additional subscribers.
@ -659,7 +659,7 @@ it('ensures a subscriber is not mistakenly overwritten', async () => {
<Count2 />
<Count1 />
<Count1 />
</StrictMode>
</StrictMode>,
)
// Call all subscribers
@ -686,7 +686,7 @@ it('works with non-object state', async () => {
const { getByText, findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 1')

View File

@ -43,7 +43,7 @@ it('creates and uses context store', async () => {
<Provider createStore={createStore}>
<Counter />
</Provider>
</>
</>,
)
await findByText('count: 1')
@ -70,7 +70,7 @@ it('uses context store with selectors', async () => {
<Provider createStore={createStore}>
<Counter />
</Provider>
</>
</>,
)
await findByText('count: 1')
@ -82,7 +82,7 @@ it('uses context store api', async () => {
subscribeWithSelector((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}))
})),
)
type CustomStore = ReturnType<typeof createStore>
@ -95,9 +95,9 @@ it('uses context store api', async () => {
() =>
storeApi.subscribe(
(state) => state.count,
() => setCount(storeApi.getState().count)
() => setCount(storeApi.getState().count),
),
[storeApi]
[storeApi],
)
useEffect(() => {
storeApi.setState({ count: storeApi.getState().count + 1 })
@ -116,7 +116,7 @@ it('uses context store api', async () => {
<Provider createStore={createStore}>
<Counter />
</Provider>
</>
</>,
)
await findByText('count: 1')
@ -152,7 +152,7 @@ it('throws error when not using provider', async () => {
<ErrorBoundary>
<Component />
</ErrorBoundary>
</StrictMode>
</StrictMode>,
)
await findByText('errored')
})
@ -169,6 +169,6 @@ const expectAreTypesEqual = <A, B>() => ({
toBe: (
_: (<T>() => T extends B ? 1 : 0) extends <T>() => T extends A ? 1 : 0
? true
: false
: false,
) => {},
})

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,7 @@ describe('counter state spec (single middleware)', () => {
set((state) => {
state.count = get().count + 1
}),
}))
})),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -58,7 +58,7 @@ describe('counter state spec (single middleware)', () => {
TestComponent
const _testSubtyping: StoreApi<object> = createStore(
immer(() => ({ count: 0 }))
immer(() => ({ count: 0 })),
)
})
@ -73,8 +73,8 @@ describe('counter state spec (single middleware)', () => {
return state
}
},
{ count: 0 }
)
{ count: 0 },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -86,7 +86,7 @@ describe('counter state spec (single middleware)', () => {
TestComponent
const _testSubtyping: StoreApi<object> = createStore(
redux((x) => x, { count: 0 })
redux((x) => x, { count: 0 }),
)
})
@ -97,8 +97,8 @@ describe('counter state spec (single middleware)', () => {
count: 0,
inc: () => set({ count: get().count + 1 }, false, 'inc'),
}),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -113,7 +113,7 @@ describe('counter state spec (single middleware)', () => {
TestComponent
const _testSubtyping: StoreApi<object> = createStore(
devtools(() => ({ count: 0 }))
devtools(() => ({ count: 0 })),
)
})
@ -122,7 +122,7 @@ describe('counter state spec (single middleware)', () => {
subscribeWithSelector((set, get) => ({
count: 1,
inc: () => set({ count: get().count + 1 }, false),
}))
})),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -133,14 +133,14 @@ describe('counter state spec (single middleware)', () => {
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
(count) => console.log(count * 2),
)
return <></>
}
TestComponent
const _testSubtyping: StoreApi<object> = createStore(
subscribeWithSelector(() => ({ count: 0 }))
subscribeWithSelector(() => ({ count: 0 })),
)
})
@ -148,7 +148,7 @@ describe('counter state spec (single middleware)', () => {
const useBoundStore = create(
combine({ count: 1 }, (set, get) => ({
inc: () => set({ count: get().count + 1 }, false),
}))
})),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -162,7 +162,7 @@ describe('counter state spec (single middleware)', () => {
TestComponent
const _testSubtyping: StoreApi<object> = createStore(
combine({ count: 0 }, () => ({}))
combine({ count: 0 }, () => ({})),
)
})
@ -173,8 +173,8 @@ describe('counter state spec (single middleware)', () => {
count: 1,
inc: () => set({ count: get().count + 1 }, false),
}),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -189,7 +189,7 @@ describe('counter state spec (single middleware)', () => {
TestComponent
const _testSubtyping: StoreApi<object> = createStore(
persist(() => ({ count: 0 }), { name: 'prefix' })
persist(() => ({ count: 0 }), { name: 'prefix' }),
)
})
@ -200,8 +200,8 @@ describe('counter state spec (single middleware)', () => {
count: 1,
inc: () => set({ count: get().count + 1 }, false),
}),
{ name: 'prefix', partialize: (s) => s.count }
)
{ name: 'prefix', partialize: (s) => s.count },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -227,8 +227,8 @@ describe('counter state spec (single middleware)', () => {
count: 1,
inc: () => set({ count: get().count + 1 }, false),
}),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -256,12 +256,12 @@ describe('counter state spec (double middleware)', () => {
state.count = get().count + 1
},
false,
{ type: 'inc', by: 1 }
{ type: 'inc', by: 1 },
),
}),
{ name: 'prefix' }
)
)
{ name: 'prefix' },
),
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -288,10 +288,10 @@ describe('counter state spec (double middleware)', () => {
return state
}
},
{ count: 0 }
{ count: 0 },
),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -310,8 +310,8 @@ describe('counter state spec (double middleware)', () => {
combine({ count: 1 }, (set, get) => ({
inc: () => set({ count: get().count + 1 }, false, 'inc'),
})),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -331,8 +331,8 @@ describe('counter state spec (double middleware)', () => {
subscribeWithSelector(
combine({ count: 1 }, (set, get) => ({
inc: () => set({ count: get().count + 1 }, false),
}))
)
})),
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -343,7 +343,7 @@ describe('counter state spec (double middleware)', () => {
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
(count) => console.log(count * 2),
)
return <></>
}
@ -357,8 +357,8 @@ describe('counter state spec (double middleware)', () => {
count: 1,
inc: () => set({ count: get().count + 1 }, false, 'inc'),
})),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -369,7 +369,7 @@ describe('counter state spec (double middleware)', () => {
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
(count) => console.log(count * 2),
)
useBoundStore.setState({ count: 0 }, false, 'reset')
return <></>
@ -385,10 +385,10 @@ describe('counter state spec (double middleware)', () => {
count: 1,
inc: () => set({ count: get().count + 1 }, false, 'inc'),
}),
{ name: 'count' }
{ name: 'count' },
),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -417,10 +417,10 @@ describe('counter state spec (triple middleware)', () => {
state.count = get().count + 1
}),
})),
{ name: 'count' }
{ name: 'count' },
),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -442,10 +442,10 @@ describe('counter state spec (triple middleware)', () => {
subscribeWithSelector(
combine({ count: 1 }, (set, get) => ({
inc: () => set({ count: get().count + 1 }, false, 'inc'),
}))
})),
),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -456,7 +456,7 @@ describe('counter state spec (triple middleware)', () => {
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
(count) => console.log(count * 2),
)
useBoundStore.setState({ count: 0 }, false, 'reset')
return <></>
@ -473,11 +473,11 @@ describe('counter state spec (triple middleware)', () => {
count: 0,
inc: () => set({ count: get().count + 1 }, false),
}),
{ name: 'count' }
)
{ name: 'count' },
),
),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -488,7 +488,7 @@ describe('counter state spec (triple middleware)', () => {
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
(count) => console.log(count * 2),
)
useBoundStore.setState({ count: 0 }, false, 'reset')
useBoundStore.persist.hasHydrated()
@ -511,11 +511,11 @@ describe('counter state spec (quadruple middleware)', () => {
state.count = get().count + 1
}),
})),
{ name: 'count' }
)
{ name: 'count' },
),
),
{ name: 'prefix' }
)
{ name: 'prefix' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -526,7 +526,7 @@ describe('counter state spec (quadruple middleware)', () => {
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
(count) => console.log(count * 2),
)
useBoundStore.setState({ count: 0 }, false, 'reset')
useBoundStore.persist.hasHydrated()
@ -544,9 +544,9 @@ describe('more complex state spec with subscribeWithSelector', () => {
() => ({
foo: true,
}),
{ name: 'name' }
)
)
{ name: 'name' },
),
),
)
const TestComponent = () => {
useBoundStore((s) => s.foo)
@ -554,7 +554,7 @@ describe('more complex state spec with subscribeWithSelector', () => {
useBoundStore.getState().foo
useBoundStore.subscribe(
(state) => state.foo,
(foo) => console.log(foo)
(foo) => console.log(foo),
)
useBoundStore.persist.hasHydrated()
return <></>
@ -571,8 +571,8 @@ describe('more complex state spec with subscribeWithSelector', () => {
() =>
({
foo: 1,
}) as MyState // NOTE: Asserting the entire state works too.
)
}) as MyState, // NOTE: Asserting the entire state works too.
),
)
const TestComponent = () => {
useBoundStore((s) => s.foo)
@ -580,7 +580,7 @@ describe('more complex state spec with subscribeWithSelector', () => {
useBoundStore.getState().foo
useBoundStore.subscribe(
(state) => state.foo,
(foo) => console.log(foo)
(foo) => console.log(foo),
)
return <></>
}
@ -602,8 +602,8 @@ describe('more complex state spec with subscribeWithSelector', () => {
set({ authenticated: true })
},
}),
{ name: 'auth-store' }
)
{ name: 'auth-store' },
),
)
const TestComponent = () => {
useBoundStore((s) => s.authenticated)
@ -633,9 +633,9 @@ describe('create with explicitly annotated mutators', () => {
count: 0,
inc: () => set({ count: get().count + 1 }, false),
}),
{ name: 'count' }
)
)
{ name: 'count' },
),
),
)
const TestComponent = () => {
useBoundStore((s) => s.count) * 2
@ -646,7 +646,7 @@ describe('create with explicitly annotated mutators', () => {
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
(count) => console.log(count * 2),
)
useBoundStore.setState({ count: 0 }, false)
useBoundStore.persist.hasHydrated()

View File

@ -62,8 +62,8 @@ describe('persist middleware with async configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
}
)
},
),
)
function Counter() {
@ -78,14 +78,14 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 0, name: empty')
await findByText('count: 42, name: test-storage')
expect(onRehydrateStorageSpy).toBeCalledWith(
{ count: 42, name: 'test-storage' },
undefined
undefined,
)
})
@ -105,7 +105,7 @@ describe('persist middleware with async configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
function Counter() {
@ -116,14 +116,14 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 0')
await waitFor(() => {
expect(onRehydrateStorageSpy).toBeCalledWith(
undefined,
new Error('getItem error')
new Error('getItem error'),
)
})
})
@ -138,7 +138,7 @@ describe('persist middleware with async configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
return { useBoundStore, onRehydrateStorageSpy }
}
@ -154,7 +154,7 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 0')
await waitFor(() => {
@ -166,7 +166,7 @@ describe('persist middleware with async configuration', () => {
await findByText('count: 42')
expect(setItemSpy).toBeCalledWith(
'test-storage',
JSON.stringify({ state: { count: 42 }, version: 0 })
JSON.stringify({ state: { count: 42 }, version: 0 }),
)
// Create the same store a second time and check if the persisted state
@ -183,7 +183,7 @@ describe('persist middleware with async configuration', () => {
const { findByText: findByText2 } = render(
<StrictMode>
<Counter2 />
</StrictMode>
</StrictMode>,
)
await findByText2('count: 42')
await waitFor(() => {
@ -213,7 +213,7 @@ describe('persist middleware with async configuration', () => {
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
migrate: migrateSpy,
})
}),
)
function Counter() {
@ -224,7 +224,7 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 0')
@ -235,7 +235,7 @@ describe('persist middleware with async configuration', () => {
JSON.stringify({
state: { count: 99 },
version: 13,
})
}),
)
expect(onRehydrateStorageSpy).toBeCalledWith({ count: 99 }, undefined)
})
@ -266,8 +266,8 @@ describe('persist middleware with async configuration', () => {
{
name: 'test-storage',
storage: createJSONStorage(() => storage),
}
)
},
),
)
function Component() {
@ -286,7 +286,7 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Component />
</StrictMode>
</StrictMode>,
)
await findByText('count: 42')
@ -296,7 +296,7 @@ describe('persist middleware with async configuration', () => {
expect.objectContaining({
count: 42,
name: 'test',
})
}),
)
})
@ -319,7 +319,7 @@ describe('persist middleware with async configuration', () => {
version: 13,
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
function Counter() {
@ -330,7 +330,7 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 0')
@ -363,7 +363,7 @@ describe('persist middleware with async configuration', () => {
throw new Error('migrate error')
},
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
function Counter() {
@ -374,14 +374,14 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 0')
await waitFor(() => {
expect(onRehydrateStorageSpy).toBeCalledWith(
undefined,
new Error('migrate error')
new Error('migrate error'),
)
})
})
@ -400,7 +400,7 @@ describe('persist middleware with async configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: onRehydrateStorageSpy,
})
}),
)
/**
@ -423,7 +423,7 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 1')
@ -455,7 +455,7 @@ describe('persist middleware with async configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
function Counter() {
@ -466,14 +466,14 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 0')
await waitFor(() => {
expect(onRehydrateStorageSpy).toBeCalledWith(
{ count: 1, unstorableMethod },
undefined
undefined,
)
})
})
@ -507,7 +507,7 @@ describe('persist middleware with async configuration', () => {
...persistedState,
}
},
})
}),
)
function Counter() {
@ -518,7 +518,7 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 1')
@ -546,7 +546,7 @@ describe('persist middleware with async configuration', () => {
persist(() => ({ count: 0 }), {
name: 'test-storage',
storage: createJSONStorage(() => storage),
})
}),
)
function Counter() {
@ -557,7 +557,7 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 1')
@ -579,7 +579,7 @@ describe('persist middleware with async configuration', () => {
persist(() => ({ count: 0 }), {
name: 'test-storage',
storage: createJSONStorage(() => storage),
})
}),
)
storage.getItem = async () => storageValue
@ -600,11 +600,11 @@ describe('persist middleware with async configuration', () => {
persist(() => ({ count: 0 }), {
name: 'test-storage',
storage: createJSONStorage(() => storage),
})
}),
)
expect(useBoundStore.persist.hasHydrated()).toBe(false)
await new Promise((resolve) =>
useBoundStore.persist.onFinishHydration(resolve)
useBoundStore.persist.onFinishHydration(resolve),
)
expect(useBoundStore.persist.hasHydrated()).toBe(true)
@ -634,8 +634,8 @@ describe('persist middleware with async configuration', () => {
storage: storage,
onRehydrateStorage: () => onRehydrateStorageSpy,
skipHydration: true,
}
)
},
),
)
expect(useBoundStore.getState()).toEqual({
@ -659,7 +659,7 @@ describe('persist middleware with async configuration', () => {
})
expect(onRehydrateStorageSpy).toBeCalledWith(
{ count: 42, name: 'test-storage' },
undefined
undefined,
)
})
@ -680,8 +680,8 @@ describe('persist middleware with async configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => (s) => s?.inc(),
}
)
},
),
)
function Counter() {
@ -692,7 +692,7 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<Counter />
</StrictMode>
</StrictMode>,
)
await findByText('count: 2')
@ -721,8 +721,8 @@ describe('persist middleware with async configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage, { replacer, reviver }),
onRehydrateStorage: () => onRehydrateStorageSpy,
}
)
},
),
)
function MapDisplay() {
@ -733,13 +733,13 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<MapDisplay />
</StrictMode>
</StrictMode>,
)
await findByText('map: bar')
expect(onRehydrateStorageSpy).toBeCalledWith(
{ map: new Map([['foo', 'bar']]) },
undefined
undefined,
)
})
@ -754,7 +754,7 @@ describe('persist middleware with async configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage, { replacer, reviver }),
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
return { useBoundStore, onRehydrateStorageSpy }
}
@ -770,7 +770,7 @@ describe('persist middleware with async configuration', () => {
const { findByText } = render(
<StrictMode>
<MapDisplay />
</StrictMode>
</StrictMode>,
)
await findByText('map-content:')
await waitFor(() => {
@ -787,7 +787,7 @@ describe('persist middleware with async configuration', () => {
JSON.stringify({
state: { map: { type: 'Map', value: [['foo', 'bar']] } },
version: 0,
})
}),
)
// Create the same store a second time and check if the persisted state
@ -804,13 +804,13 @@ describe('persist middleware with async configuration', () => {
const { findByText: findByText2 } = render(
<StrictMode>
<MapDisplay2 />
</StrictMode>
</StrictMode>,
)
await findByText2('map-content: bar')
await waitFor(() => {
expect(onRehydrateStorageSpy2).toBeCalledWith(
{ map: updatedMap },
undefined
undefined,
)
})
})

View File

@ -58,8 +58,8 @@ describe('persist middleware with sync configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
}
)
},
),
)
expect(useBoundStore.getState()).toEqual({
@ -68,7 +68,7 @@ describe('persist middleware with sync configuration', () => {
})
expect(onRehydrateStorageSpy).toBeCalledWith(
{ count: 42, name: 'test-storage' },
undefined
undefined,
)
})
@ -87,7 +87,7 @@ describe('persist middleware with sync configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => spy,
})
}),
)
expect(spy).toBeCalledWith(undefined, new Error('getItem error'))
@ -103,7 +103,7 @@ describe('persist middleware with sync configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
return { useBoundStore, onRehydrateStorageSpy }
}
@ -118,7 +118,7 @@ describe('persist middleware with sync configuration', () => {
expect(useBoundStore.getState()).toEqual({ count: 42 })
expect(setItemSpy).toBeCalledWith(
'test-storage',
JSON.stringify({ state: { count: 42 }, version: 0 })
JSON.stringify({ state: { count: 42 }, version: 0 }),
)
// Create the same store a second time and check if the persisted state
@ -153,7 +153,7 @@ describe('persist middleware with sync configuration', () => {
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
migrate: migrateSpy,
})
}),
)
expect(useBoundStore.getState()).toEqual({ count: 99 })
@ -163,7 +163,7 @@ describe('persist middleware with sync configuration', () => {
JSON.stringify({
state: { count: 99 },
version: 13,
})
}),
)
expect(onRehydrateStorageSpy).toBeCalledWith({ count: 99 }, undefined)
})
@ -187,7 +187,7 @@ describe('persist middleware with sync configuration', () => {
version: 13,
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
expect(useBoundStore.getState()).toEqual({ count: 0 })
@ -217,13 +217,13 @@ describe('persist middleware with sync configuration', () => {
throw new Error('migrate error')
},
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
expect(useBoundStore.getState()).toEqual({ count: 0 })
expect(onRehydrateStorageSpy).toBeCalledWith(
undefined,
new Error('migrate error')
new Error('migrate error'),
)
})
@ -241,7 +241,7 @@ describe('persist middleware with sync configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: onRehydrateStorageSpy,
})
}),
)
/**
@ -281,7 +281,7 @@ describe('persist middleware with sync configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
const expectedState = { count: 1, unstorableMethod }
@ -319,7 +319,7 @@ describe('persist middleware with sync configuration', () => {
...persistedState,
}
},
})
}),
)
expect(useBoundStore.getState()).toEqual({
@ -346,7 +346,7 @@ describe('persist middleware with sync configuration', () => {
persist(() => ({ count: 0 }), {
name: 'test-storage',
storage: createJSONStorage(() => storage),
})
}),
)
expect(useBoundStore.getState()).toEqual({
@ -393,8 +393,8 @@ describe('persist middleware with sync configuration', () => {
array: state.array.filter((e) => e.value !== '1'),
}
},
}
)
},
),
)
useBoundStore.setState({})
@ -415,7 +415,7 @@ describe('persist middleware with sync configuration', () => {
],
},
version: 0,
})
}),
)
})
@ -430,7 +430,7 @@ describe('persist middleware with sync configuration', () => {
persist(() => ({ count: 0 }), {
name: 'test-storage',
storage: createJSONStorage(() => storage),
})
}),
)
expect(useBoundStore.persist.getOptions().name).toBeDefined()
expect(useBoundStore.persist.getOptions().name).toBe('test-storage')
@ -450,26 +450,26 @@ describe('persist middleware with sync configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
partialize: (s) => s as Partial<typeof s>,
})
}),
)
useBoundStore.setState({})
expect(setItemSpy).toBeCalledWith(
'test-storage',
'{"state":{"count":0},"version":0}'
'{"state":{"count":0},"version":0}',
)
useBoundStore.persist.setOptions({
name: 'test-storage-2',
partialize: (state) =>
Object.fromEntries(
Object.entries(state).filter(([key]) => key !== 'count')
Object.entries(state).filter(([key]) => key !== 'count'),
),
})
useBoundStore.setState({})
expect(setItemSpy).toBeCalledWith(
'test-storage-2',
'{"state":{},"version":0}'
'{"state":{},"version":0}',
)
})
@ -486,7 +486,7 @@ describe('persist middleware with sync configuration', () => {
persist(() => ({ count: 0 }), {
name: 'test-storage',
storage: createJSONStorage(() => storage),
})
}),
)
useBoundStore.persist.clearStorage()
@ -506,7 +506,7 @@ describe('persist middleware with sync configuration', () => {
persist(() => ({ count: 0 }), {
name: 'test-storage',
storage: createJSONStorage(() => storage),
})
}),
)
storage.getItem = () => storageValue
@ -527,7 +527,7 @@ describe('persist middleware with sync configuration', () => {
persist(() => ({ count: 0 }), {
name: 'test-storage',
storage: createJSONStorage(() => storage),
})
}),
)
expect(useBoundStore.persist.hasHydrated()).toBe(true)
@ -555,14 +555,14 @@ describe('persist middleware with sync configuration', () => {
persist(() => ({ count: 0 }), {
name: 'test-storage',
storage: createJSONStorage(() => storage),
})
}),
)
const hydrateUnsub1 = useBoundStore.persist.onHydrate(onHydrateSpy1)
useBoundStore.persist.onHydrate(onHydrateSpy2)
const finishHydrationUnsub1 = useBoundStore.persist.onFinishHydration(
onFinishHydrationSpy1
onFinishHydrationSpy1,
)
useBoundStore.persist.onFinishHydration(onFinishHydrationSpy2)
@ -606,8 +606,8 @@ describe('persist middleware with sync configuration', () => {
storage: storage,
onRehydrateStorage: () => onRehydrateStorageSpy,
skipHydration: true,
}
)
},
),
)
expect(useBoundStore.getState()).toEqual({
@ -631,7 +631,7 @@ describe('persist middleware with sync configuration', () => {
})
expect(onRehydrateStorageSpy).toBeCalledWith(
{ count: 42, name: 'test-storage' },
undefined
undefined,
)
})
@ -652,8 +652,8 @@ describe('persist middleware with sync configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => (s) => s?.inc(),
}
)
},
),
)
expect(useBoundStore.getState().count).toEqual(2)
@ -680,8 +680,8 @@ describe('persist middleware with sync configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage),
onRehydrateStorage: () => onRehydrateStorageSpy,
}
)
},
),
)
const updatedMap = map.set('foo', 'bar')
@ -702,7 +702,7 @@ describe('persist middleware with sync configuration', () => {
name: 'test-storage',
storage: createJSONStorage(() => storage, { replacer, reviver }),
onRehydrateStorage: () => onRehydrateStorageSpy,
})
}),
)
return { useBoundStore, onRehydrateStorageSpy }
}
@ -723,7 +723,7 @@ describe('persist middleware with sync configuration', () => {
JSON.stringify({
state: { map: { type: 'Map', value: [['foo', 'bar']] } },
version: 0,
})
}),
)
// Create the same store a second time and check if the persisted state
@ -735,7 +735,7 @@ describe('persist middleware with sync configuration', () => {
expect(useBoundStore2.getState()).toEqual({ map: updatedMap })
expect(onRehydrateStorageSpy2).toBeCalledWith(
{ map: updatedMap },
undefined
undefined,
)
})
})

View File

@ -24,7 +24,7 @@ describe('types', () => {
const Component = () => {
const refetchTimestamp = useBoundStore(
(state) => state.refetchTimestamp,
shallow
shallow,
)
return <>{refetchTimestamp.toUpperCase()}</>
}
@ -61,7 +61,7 @@ describe('useShallow', () => {
it('input and output selectors always return shallow equal values', () => {
const res = render(
<TestUseShallowSimple state={{ a: 1, b: 2 }} selector={Object.keys} />
<TestUseShallowSimple state={{ a: 1, b: 2 }} selector={Object.keys} />,
)
expect(testUseShallowSimpleCallback).toHaveBeenCalledTimes(0)
@ -77,7 +77,7 @@ describe('useShallow', () => {
<TestUseShallowSimple
state={{ a: 1, b: 2, c: 3 }}
selector={Object.keys}
/>
/>,
)
fireEvent.click(res.getByTestId('test-shallow'))
@ -92,7 +92,7 @@ describe('useShallow', () => {
it('returns the previously computed instance when possible', () => {
const state = { a: 1, b: 2 }
const res = render(
<TestUseShallowSimple state={state} selector={Object.keys} />
<TestUseShallowSimple state={state} selector={Object.keys} />,
)
fireEvent.click(res.getByTestId('test-shallow'))
@ -106,7 +106,7 @@ describe('useShallow', () => {
<TestUseShallowSimple
state={state}
selector={(state) => Object.keys(state)}
/>
/>,
)
fireEvent.click(res.getByTestId('test-shallow'))
@ -122,7 +122,7 @@ describe('useShallow', () => {
it('only re-renders if selector output has changed according to shallow', () => {
let countRenders = 0
const useMyStore = create(
(): Record<string, unknown> => ({ a: 1, b: 2, c: 3 })
(): Record<string, unknown> => ({ a: 1, b: 2, c: 3 }),
)
const TestShallow = ({
selector = (state) => Object.keys(state).sort(),
@ -158,18 +158,19 @@ describe('useShallow', () => {
it('does not cause stale closure issues', () => {
const useMyStore = create(
(): Record<string, unknown> => ({ a: 1, b: 2, c: 3 })
(): Record<string, unknown> => ({ a: 1, b: 2, c: 3 }),
)
const TestShallowWithState = () => {
const [count, setCount] = useState(0)
const output = useMyStore(
useShallow((state) => Object.keys(state).concat([count.toString()]))
useShallow((state) => Object.keys(state).concat([count.toString()])),
)
return (
<div
data-testid="test-shallow"
onClick={() => setCount((prev) => ++prev)}>
onClick={() => setCount((prev) => ++prev)}
>
{output.join(',')}
</div>
)

View File

@ -23,7 +23,7 @@ function Counter() {
({ bears, increasePopulation }) => ({
bears,
increasePopulation,
})
}),
)
useEffect(() => {
@ -39,13 +39,13 @@ describe.skipIf(!React.version.startsWith('18'))(
it('should handle different states between server and client correctly', async () => {
const { hydrateRoot } =
await vi.importActual<typeof import('react-dom/client')>(
'react-dom/client'
'react-dom/client',
)
const markup = renderToString(
<React.Suspense fallback={<div>Loading...</div>}>
<Counter />
</React.Suspense>
</React.Suspense>,
)
const container = document.createElement('div')
@ -59,7 +59,7 @@ describe.skipIf(!React.version.startsWith('18'))(
container,
<React.Suspense fallback={<div>Loading...</div>}>
<Counter />
</React.Suspense>
</React.Suspense>,
)
})
@ -67,5 +67,5 @@ describe.skipIf(!React.version.startsWith('18'))(
expect(bearCountText).not.toBeNull()
document.body.removeChild(container)
})
}
},
)

View File

@ -27,7 +27,7 @@ describe('subscribe()', () => {
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
subscribeWithSelector(() => initialState),
)
subscribe((s) => s.value, spy)
@ -39,7 +39,7 @@ describe('subscribe()', () => {
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
subscribeWithSelector(() => initialState),
)
subscribe((s) => s.value, spy)
@ -52,7 +52,7 @@ describe('subscribe()', () => {
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
subscribeWithSelector(() => initialState),
)
subscribe((s) => s, spy, { equalityFn: () => true })
@ -64,7 +64,7 @@ describe('subscribe()', () => {
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
subscribeWithSelector(() => initialState),
)
subscribe((s) => s.value, spy, { equalityFn: () => false })
@ -77,7 +77,7 @@ describe('subscribe()', () => {
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { setState, subscribe } = create(
subscribeWithSelector(() => initialState)
subscribeWithSelector(() => initialState),
)
const unsub = subscribe((s) => s.value, spy)
@ -94,7 +94,7 @@ describe('subscribe()', () => {
const spy = vi.fn()
const initialState = { value: 1, other: 'a' }
const { getState, setState, subscribe } = create(
subscribeWithSelector(() => initialState)
subscribeWithSelector(() => initialState),
)
const isRoughEqual = (x: number, y: number) => Math.abs(x - y) < 1

View File

@ -5,7 +5,7 @@ type ReplacedMap = {
export const replacer = (
key: string,
value: unknown
value: unknown,
): ReplacedMap | unknown => {
if (value instanceof Map) {
return {

View File

@ -30,7 +30,7 @@ it('can use exposed types', () => {
numGet: () => 2,
}
const partialFn: (state: ExampleState) => Partial<ExampleState> = (
state
state,
) => ({
...state,
num: 2,
@ -82,7 +82,7 @@ it('can use exposed types', () => {
_destroy: StoreApi<ExampleState>['destroy'],
_equalityFn: (a: ExampleState, b: ExampleState) => boolean,
_stateCreator: StateCreator<ExampleState>,
_useBoundStore: UseBoundStore<StoreApi<ExampleState>>
_useBoundStore: UseBoundStore<StoreApi<ExampleState>>,
) {
expect(true).toBeTruthy()
}
@ -99,7 +99,7 @@ it('can use exposed types', () => {
storeApi.destroy,
equalityFn,
stateCreator,
useBoundStore
useBoundStore,
)
})

View File

@ -103,7 +103,7 @@ it('can set the store without merging', () => {
const { setState, getState } = createStore<{ a: number } | { b: number }>(
(_set) => ({
a: 1,
})
}),
)
// Should override the state instead of merging.

View File

@ -15,15 +15,15 @@ describe('shallow', () => {
it('compares objects', () => {
expect(shallow({ foo: 'bar', asd: 123 }, { foo: 'bar', asd: 123 })).toBe(
true
true,
)
expect(
shallow({ foo: 'bar', asd: 123 }, { foo: 'bar', foobar: true })
shallow({ foo: 'bar', asd: 123 }, { foo: 'bar', foobar: true }),
).toBe(false)
expect(
shallow({ foo: 'bar', asd: 123 }, { foo: 'bar', asd: 123, foobar: true })
shallow({ foo: 'bar', asd: 123 }, { foo: 'bar', asd: 123, foobar: true }),
).toBe(false)
})
@ -33,7 +33,7 @@ describe('shallow', () => {
expect(shallow([1, 2, 3], [2, 3, 4])).toBe(false)
expect(
shallow([{ foo: 'bar' }, { asd: 123 }], [{ foo: 'bar' }, { asd: 123 }])
shallow([{ foo: 'bar' }, { asd: 123 }], [{ foo: 'bar' }, { asd: 123 }]),
).toBe(false)
expect(shallow([{ foo: 'bar' }], [{ foo: 'bar', asd: 123 }])).toBe(false)
@ -47,22 +47,22 @@ describe('shallow', () => {
expect(
shallow(
createMap({ foo: 'bar', asd: 123 }),
createMap({ foo: 'bar', asd: 123 })
)
createMap({ foo: 'bar', asd: 123 }),
),
).toBe(true)
expect(
shallow(
createMap({ foo: 'bar', asd: 123 }),
createMap({ foo: 'bar', foobar: true })
)
createMap({ foo: 'bar', foobar: true }),
),
).toBe(false)
expect(
shallow(
createMap({ foo: 'bar', asd: 123 }),
createMap({ foo: 'bar', asd: 123, foobar: true })
)
createMap({ foo: 'bar', asd: 123, foobar: true }),
),
).toBe(false)
})
@ -72,7 +72,7 @@ describe('shallow', () => {
expect(shallow(new Set(['bar', 123]), new Set(['bar', 2]))).toBe(false)
expect(shallow(new Set(['bar', 123]), new Set(['bar', 123, true]))).toBe(
false
false,
)
})
@ -98,8 +98,8 @@ describe('unsupported cases', () => {
expect(
shallow(
new Date('2022-07-19T00:00:00.000Z'),
new Date('2022-07-20T00:00:00.000Z')
)
new Date('2022-07-20T00:00:00.000Z'),
),
).not.toBe(false)
})
})