Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: pmndrs/zustand
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v4.3.8
Choose a base ref
...
head repository: pmndrs/zustand
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v4.3.9
Choose a head ref

Commits on May 5, 2023

  1. Copy the full SHA
    639aa00 View commit details

Commits on May 7, 2023

  1. Add section for usage of persist middleware with NextJS (#1782)

    * Add section for usage of persist middleware with NextJS
    
    I have spent the last 1h30m trying to find the solution for `Hydration failed because the initial UI does not match what was rendered on the server` and after digging a lot I found the solution.
    So i thought: Maybe this could be on official documentation!
    So I made it. It's just copy and paste but at least it will be easier for future folks trying to solve the same problem
    
    * ran yarn prettier
    
    * fix typos
    
    * Update docs/integrations/persisting-store-data.md
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    
    * splitting long lines into smaller ones
    
    following the suggestion of PR
    
    * commit suggestion of changes in PR
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    
    * commit suggestion of changes in PR
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    
    * commit suggestion of changes in PR
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    
    * commit suggestion of changes in PR
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    
    * applying changes requested in PR
    
    ---------
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    Nipodemos and sewera authored May 7, 2023
    Copy the full SHA
    65d2bc0 View commit details

Commits on May 11, 2023

  1. Copy the full SHA
    614bf5f View commit details

Commits on May 17, 2023

  1. Copy the full SHA
    56ab6db View commit details
  2. docs: persist and connect state with url (#1804)

    * docs: persist and connect state with url
    
    * ran prettier
    
    * remove line
    
    * Apply suggestions from code review
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    
    * from review comments
    
    ---------
    
    Co-authored-by: celinecheng <celine.cheng@capitalone.com>
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    3 people authored May 17, 2023
    Copy the full SHA
    286e443 View commit details
  3. Update Recipes persist example to match example in Persisting Store D…

    …ata integration (#1813)
    
    Replace the deprecated `getStorage` option with the new `storage` option with `createJSONStorage`.
    wmcb91 authored May 17, 2023
    Copy the full SHA
    d61b70f View commit details

Commits on May 20, 2023

  1. Update readme.md: add pnpm as install option (#1819)

    * Update readme.md: add pnpm as install option
    
    * Update readme.md
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    
    ---------
    
    Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    3 people authored May 20, 2023
    Copy the full SHA
    dfa779b View commit details

Commits on May 22, 2023

  1. Update third-party-libraries.md (#1816)

    * Update third-party-libraries.md
    
    * Update docs/integrations/third-party-libraries.md
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    
    * Update third-party-libraries.md
    
    ---------
    
    Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    3 people authored May 22, 2023
    Copy the full SHA
    8cb150a View commit details

Commits on May 26, 2023

  1. fix useHydration hook (#1826)

    The initialization type of `useState` is incorrect. hydrated needs to be of boolean type, whereas the original `useBoundStore.persist.hasHydrated` is a function. This will lead to errors, such as during the static build of frameworks like Next.js.
    203x authored May 26, 2023
    Copy the full SHA
    ac4ec46 View commit details
  2. Update third-party-libraries.md (#1827)

    rename npm package zustand-fetching -> leiten-zustand
    Hecmatyar authored May 26, 2023
    Copy the full SHA
    eb5ec74 View commit details

Commits on Jun 7, 2023

  1. Copy the full SHA
    618c2e5 View commit details
  2. docs: added a new third party lib (#1843)

    * docs: added a new third party lib
    
    * chore: prettier
    Romainlg29 authored Jun 7, 2023
    Copy the full SHA
    3a365a0 View commit details
  3. Copy the full SHA
    84c7323 View commit details

Commits on Jun 10, 2023

  1. Added zustand-ards to the third-party libraries list (#1856)

    * Added zustand-ards to the third-party libraries list
    
    * Update third-party-libraries.md
    ivoilic authored Jun 10, 2023
    Copy the full SHA
    a534335 View commit details

Commits on Jun 18, 2023

  1. docs: refine flux inspired docs to make pattern inspiration clearer (#…

    …1874)
    
    * docs: refine flux inspired docs to make pattern inspiration clearer
    
    * docs: remove the immutable note in the flux inspired docs
    chrisk-7777 authored Jun 18, 2023
    Copy the full SHA
    e8597ae View commit details

Commits on Jun 21, 2023

  1. Copy the full SHA
    7276b53 View commit details

Commits on Jun 22, 2023

  1. Improve testing docs (#1875)

    * Update testing docs (wip)
    
    * WIP
    
    * WIP
    
    * Update testing docs
    
    * Minor updates
    dbritto-dev authored Jun 22, 2023
    Copy the full SHA
    9333eb6 View commit details

Commits on Jun 23, 2023

  1. Copy the full SHA
    3584d50 View commit details

Commits on Jun 27, 2023

  1. Testing docs minor fixes (#1898)

    * Minor fixes
    
    * Update testing.md
    
    * Update testing.md
    dbritto-dev authored Jun 27, 2023
    Copy the full SHA
    1b557cb View commit details

Commits on Jun 29, 2023

  1. Copy the full SHA
    d4e5aed View commit details

Commits on Jun 30, 2023

  1. Copy the full SHA
    58947a5 View commit details

Commits on Jul 3, 2023

  1. 📝 Fixed some grammar and punctuation (#1913)

    * 📝 Fixed some typos
    
    * Update readme.md
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    
    * Update readme.md
    
    ---------
    
    Co-authored-by: Blazej Sewera <code@sewera.dev>
    thedipankarroy and sewera authored Jul 3, 2023
    Copy the full SHA
    1a92e94 View commit details

Commits on Jul 4, 2023

  1. fix(build): mode env for "import" condition" (#1845)

    * fix(build): mode env for "import" condition"
    
    * another way
    
    * yet another way
    dai-shi authored Jul 4, 2023
    Copy the full SHA
    f0d9d98 View commit details
  2. Copy the full SHA
    16cafca View commit details
  3. 4.3.9

    dai-shi committed Jul 4, 2023
    Copy the full SHA
    ea40986 View commit details
4 changes: 2 additions & 2 deletions .github/workflows/test-multiple-versions.yml
Original file line number Diff line number Diff line change
@@ -33,8 +33,8 @@ jobs:
- 18.0.0
- 18.1.0
- 18.2.0
- 18.3.0-canary-aef7ce554-20230503
- 0.0.0-experimental-aef7ce554-20230503
- 18.3.0-canary-53ac21937-20230703
- 0.0.0-experimental-53ac21937-20230703
devtools-skip:
- CI-MATRIX-NOSKIP
include:
2 changes: 1 addition & 1 deletion docs/guides/auto-generating-selectors.md
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ Now the selectors are auto generated and you can access them directly:
const bears = useBearStore.use.bears()

// get the action
const increase = useBearStore.use.increment()
const increment = useBearStore.use.increment()
```

## Live Demo
105 changes: 100 additions & 5 deletions docs/guides/connect-to-state-with-url-hash.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: Connect to state with URL hash
title: Connect to state with URL
nav: 12
---

## State is connected with URL hash
## Connect State with URL Hash

If you want to connect state of a store to URL hash, you can create your own hash storage.

@@ -15,7 +15,7 @@ const hashStorage: StateStorage = {
getItem: (key): string => {
const searchParams = new URLSearchParams(location.hash.slice(1))
const storedValue = searchParams.get(key) ?? ''
return storedValue
return JSON.parse(storedValue)
},
setItem: (key, newValue): void => {
const searchParams = new URLSearchParams(location.hash.slice(1))
@@ -43,6 +43,101 @@ export const useBoundStore = create(
)
```

## CodeSandbox Demo
### CodeSandbox Demo

https://codesandbox.io/s/zustand-state-with-url-hash-demo-pn20n5?file=/src/store/index.ts
https://codesandbox.io/s/zustand-state-with-url-hash-demo-f29b88?file=/src/store/index.ts

## Persist and Connect State with URL Parameters (Example: URL Query Parameters)

There are times when you want to conditionally connect the state to the URL.
This example depicts usage of the URL query parameters
while keeping it synced with another persistence implementation, like `localstorage`.

If you want the URL params to always populate, the conditional check on `getUrlSearch()` can be removed.

The implementation below will update the URL in place, without refresh, as the relevant states change.

```ts
import { create } from 'zustand'
import { persist, StateStorage, createJSONStorage } from 'zustand/middleware'

const getUrlSearch = () => {
return window.location.search.slice(1)
}

const persistentStorage: StateStorage = {
getItem: (key): string => {
// Check URL first
if (getUrlSearch()) {
const searchParams = new URLSearchParams(getUrlSearch())
const storedValue = searchParams.get(key)
return JSON.parse(storedValue)
} else {
// Otherwise, we should load from localstorage or alternative storage
return JSON.parse(localStorage.getItem(key))
}
},
setItem: (key, newValue): void => {
// Check if query params exist at all, can remove check if always want to set URL
if (getUrlSearch()) {
const searchParams = new URLSearchParams(getUrlSearch())
searchParams.set(key, JSON.stringify(newValue))
window.history.replaceState(null, null, `?${searchParams.toString()}`)
}

localStorage.setItem(key, JSON.stringify(newValue))
},
removeItem: (key): void => {
const searchParams = new URLSearchParams(getUrlSearch())
searchParams.delete(key)
window.location.search = searchParams.toString()
},
}

let localAndUrlStore = (set) => ({
typesOfFish: [],
addTypeOfFish: (fishType) =>
set((state) => ({ typesOfFish: [...state.typesOfFish, fishType] })),

numberOfBears: 0,
setNumberOfBears: (newNumber) =>
set((state) => ({ numberOfBears: newNumber })),
})

let storageOptions = {
name: 'fishAndBearsStore',
storage: persistentStorage,
}

const useLocalAndUrlStore = create(persist(localAndUrlStore, storageOptions))

export default localAndUrlStore
```

When generating the URL from a component, you can call buildShareableUrl:

```ts
const buildURLSuffix = (params, version = 0) => {
const searchParams = new URLSearchParams()

const zustandStoreParams = {
state: {
typesOfFish: params.typesOfFish,
numberOfBears: params.numberOfBears,
},
version: version, // version is here because that is included with how Zustand sets the state
}

// The URL param key should match the name of the store, as specified as in storageOptions above
searchParams.set('fishAndBearsStore', JSON.stringify(zustandStoreParams))
return searchParams.toString()
}

export const buildShareableUrl = (params, version) => {
return `${window.location.origin}?${buildURLSuffix(params, version)}`
}
```

The generated URL would look like (here without any encoding, for readability):

`https://localhost/search?fishAndBearsStore={"state":{"typesOfFish":["tilapia","salmon"],"numberOfBears":15},"version":0}}`
40 changes: 30 additions & 10 deletions docs/guides/flux-inspired-practice.md
Original file line number Diff line number Diff line change
@@ -3,27 +3,47 @@ title: Flux inspired practice
nav: 5
---

Although zustand is an unopinionated library, here are some patterns we recommend:
Although Zustand is an unopinionated library, we do recommend a few patterns.
These are inspired by practices originally found in [Flux](https://github.com/facebookarchive/flux),
and more recently [Redux](https://redux.js.org/understanding/thinking-in-redux/three-principles),
so if you are coming from another library, you should feel right at home.

- Create a single store;
- Always use `set` to define a store;
- Define your dispatch functions at the root level of the store to update one or more store slices.
However, Zustand does differ in some fundamental ways,
so some terminology may not perfectly align to other libraries.

## Recommended patterns

### Single store

Your applications global state should be located in a single Zustand store.

If you have a large application, Zustand supports [splitting the store into slices](./slices-pattern).

### Use `set` / `setState` to update the store

Always use `set` (or `setState`) to perform updates to your store.
`set` (and `setState`) ensures the described update is correctly merged and listeners are appropriately notified.

### Colocate store actions

In Zustand, state can be updated without the use of dispatched actions and reducers found in other Flux libraries.
These store actions can be added directly to the store as shown below.

Optionally, by using `setState` they can be [located external to the store](./practice-with-no-store-actions.md)

```js
const useBoundStore = create((set) => ({
storeSliceA: ...,
storeSliceB: ...,
storeSliceC: ...,
dispatchX: () => set(...),
dispatchY: () => set(...),
updateX: () => set(...),
updateY: () => set(...),
}))
```

See [Splitting the store into separate slices](./slices-pattern.md) for how to define a store with separate slices.

## Flux like patterns / "dispatching" actions
## Redux-like patterns

If you can't live without redux-like reducers, you can define a `dispatch` function on the root level of the store like so:
If you can't live without Redux-like reducers, you can define a `dispatch` function on the root level of the store:

```typescript
const types = { increase: 'INCREASE', decrease: 'DECREASE' }
2 changes: 1 addition & 1 deletion docs/guides/how-to-reset-state.md
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ const useSlice = create<State & Actions>()((set, get) => ({
Resetting multiple stores at once

```ts
import { create: _create, StateCreator } from 'zustand'
import { create as _create, StateCreator } from 'zustand'

const resetters: (() => void)[] = []

Loading