Skip to content

Commit 748caeb

Browse files
committed
Merge branch 'main' into use-sync-external-store
2 parents 90ef5c1 + 4d8003b commit 748caeb

8 files changed

Lines changed: 686 additions & 630 deletions

File tree

.github/FUNDING.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# These are supported funding model platforms
2+
3+
github: [dai-shi] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4+
patreon: # Replace with a single Patreon username
5+
open_collective: # Replace with a single Open Collective username
6+
ko_fi: # Replace with a single Ko-fi username
7+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9+
liberapay: # Replace with a single Liberapay username
10+
issuehunt: # Replace with a single IssueHunt username
11+
otechie: # Replace with a single Otechie username
12+
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13+
custom: ['https://daishi.gumroad.com/l/uaxms'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

.github/workflows/test-multiple-builds.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ jobs:
2323
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
2424
- run: yarn install --frozen-lockfile --check-files
2525
- run: yarn build
26+
- name: Use React 17 for production test
27+
if: ${{ matrix.env == 'production' }}
28+
run: |
29+
yarn add -D react@17.0.2 react-dom@17.0.2 @testing-library/react@12.1.4
2630
- name: Patch for DEV-ONLY
2731
if: ${{ matrix.env == 'development' }}
2832
run: |

.github/workflows/test-multiple-versions.yml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,9 @@ jobs:
3030
react:
3131
- 16.8.0
3232
- 17.0.0
33-
- 18.0.0-rc.1-next-629036a9c-20220224
34-
- 0.0.0-experimental-629036a9c-20220224
35-
testing: [default, alpha]
36-
exclude:
37-
- { react: 16.8.0, testing: alpha }
38-
- { react: 17.0.0, testing: alpha }
33+
- 18.0.0
34+
- 18.1.0-next-af730436c-20220405
35+
- 0.0.0-experimental-af730436c-20220405
3936
steps:
4037
- uses: actions/checkout@v2
4138
- uses: actions/setup-node@v2
@@ -44,9 +41,9 @@ jobs:
4441
cache: yarn
4542
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
4643
- run: yarn install --frozen-lockfile --check-files
47-
- name: Install alpha testing-library
48-
if: ${{ matrix.testing == 'alpha' }}
49-
run: yarn add -D @testing-library/react@alpha
44+
- name: Install legacy testing-library
45+
if: ${{ startsWith(matrix.react, '16.') || startsWith(matrix.react, '17.') }}
46+
run: yarn add -D @testing-library/react@12.1.4
5047
- name: Patch for React 16
5148
if: ${{ startsWith(matrix.react, '16.') }}
5249
run: |

package.json

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "zustand",
33
"private": true,
4-
"version": "3.7.1",
4+
"version": "3.7.2",
55
"description": "🐻 Bear necessities for state management in React",
66
"main": "./index.js",
77
"types": "./index.d.ts",
@@ -134,7 +134,7 @@
134134
"use-sync-external-store": "1.0.0"
135135
},
136136
"devDependencies": {
137-
"@babel/core": "^7.17.5",
137+
"@babel/core": "^7.17.9",
138138
"@babel/plugin-external-helpers": "^7.16.7",
139139
"@babel/plugin-transform-react-jsx": "^7.17.3",
140140
"@babel/plugin-transform-runtime": "^7.17.0",
@@ -144,41 +144,38 @@
144144
"@rollup/plugin-node-resolve": "^13.1.3",
145145
"@rollup/plugin-replace": "^4.0.0",
146146
"@rollup/plugin-typescript": "^8.3.1",
147-
"@swc/core": "^1.2.146",
147+
"@swc/core": "^1.2.164",
148148
"@swc/jest": "^0.2.20",
149-
"@testing-library/react": "^12.1.3",
149+
"@testing-library/react": "^13.0.0",
150150
"@types/jest": "^27.4.1",
151-
"@types/react": "^17.0.39",
152-
"@types/react-dom": "^17.0.11",
151+
"@types/react": "^17.0.43",
152+
"@types/react-dom": "^17.0.14",
153153
"@types/use-sync-external-store": "^0.0.3",
154-
"@typescript-eslint/eslint-plugin": "^5.12.1",
155-
"@typescript-eslint/parser": "^5.12.1",
156-
"concurrently": "^7.0.0",
157-
"esbuild": "^0.14.23",
158-
"eslint": "^8.10.0",
159-
"eslint-config-prettier": "^8.4.0",
154+
"@typescript-eslint/eslint-plugin": "^5.18.0",
155+
"@typescript-eslint/parser": "^5.18.0",
156+
"concurrently": "^7.1.0",
157+
"esbuild": "^0.14.34",
158+
"eslint": "^8.12.0",
159+
"eslint-config-prettier": "^8.5.0",
160160
"eslint-import-resolver-alias": "^1.1.2",
161-
"eslint-plugin-import": "^2.25.4",
162-
"eslint-plugin-jest": "^26.1.1",
161+
"eslint-plugin-import": "^2.26.0",
162+
"eslint-plugin-jest": "^26.1.3",
163163
"eslint-plugin-prettier": "^4.0.0",
164-
"eslint-plugin-react": "^7.29.2",
165-
"eslint-plugin-react-hooks": "^4.3.0",
164+
"eslint-plugin-react": "^7.29.4",
165+
"eslint-plugin-react-hooks": "^4.4.0",
166166
"husky": "^7.0.4",
167167
"immer": "^9.0.12",
168168
"jest": "^27.5.1",
169169
"json": "^11.0.0",
170-
"lint-staged": "^12.3.4",
171-
"prettier": "^2.5.1",
172-
"react": "^17.0.2",
173-
"react-dom": "^17.0.2",
174-
"rollup": "^2.68.0",
175-
"rollup-plugin-esbuild": "^4.8.2",
170+
"lint-staged": "^12.3.7",
171+
"prettier": "^2.6.2",
172+
"react": "^18.0.0",
173+
"react-dom": "^18.0.0",
174+
"rollup": "^2.70.1",
175+
"rollup-plugin-esbuild": "^4.9.1",
176176
"rollup-plugin-terser": "^7.0.2",
177177
"shx": "^0.3.4",
178-
"typescript": "^4.5.5"
179-
},
180-
"resolutions": {
181-
"date-fns": "2.27.0"
178+
"typescript": "^4.6.3"
182179
},
183180
"peerDependencies": {
184181
"react": ">=16.8"

readme.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ const unsub5 = useStore.subscribe(state => state.paw, console.log, { fireImmedia
200200
<summary>How to type store with `subscribeWithSelector` in TypeScript</summary>
201201
202202
```ts
203-
import create, { GetState, SetState } from 'zustand'
204-
import { StoreApiWithSubscribeWithSelector, subscribeWithSelector } from 'zustand/middleware'
203+
import create, { Mutate, GetState, SetState, StoreApi } from 'zustand'
204+
import { subscribeWithSelector } from 'zustand/middleware'
205205

206206
type BearState = {
207207
paw: boolean
@@ -212,7 +212,7 @@ const useStore = create<
212212
BearState,
213213
SetState<BearState>,
214214
GetState<BearState>,
215-
StoreApiWithSubscribeWithSelector<BearState>
215+
Mutate<StoreApi<BearState>, [["zustand/subscribeWithSelector", never]]>
216216
>(subscribeWithSelector(() => ({ paw: true, snout: true, fur: true })))
217217
```
218218

src/middleware/persist.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,10 @@ export const persist =
312312
}
313313
})
314314
.then((migratedState) => {
315-
stateFromStorage = options.merge(migratedState as S, configResult)
315+
stateFromStorage = options.merge(
316+
migratedState as S,
317+
get() ?? configResult
318+
)
316319

317320
set(stateFromStorage as S, true)
318321
return setItem()

tests/persistAsync.test.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useEffect } from 'react'
12
import { act, render, waitFor } from '@testing-library/react'
23
import create from 'zustand'
34
import { persist } from 'zustand/middleware'
@@ -217,6 +218,58 @@ describe('persist middleware with async configuration', () => {
217218
expect(onRehydrateStorageSpy).toBeCalledWith({ count: 99 }, undefined)
218219
})
219220

221+
it('can merge partial persisted state', async () => {
222+
const storage = {
223+
getItem: async () =>
224+
JSON.stringify({
225+
state: { count: 42 },
226+
}),
227+
setItem: () => {},
228+
removeItem: () => {},
229+
}
230+
231+
const useStore = create(
232+
persist(
233+
(set) => ({
234+
count: 0,
235+
name: 'unknown',
236+
setName: (name: string) => {
237+
set({ name })
238+
},
239+
}),
240+
{
241+
name: 'test-storage',
242+
getStorage: () => storage,
243+
}
244+
)
245+
)
246+
247+
function Component() {
248+
const { count, setName, name } = useStore()
249+
useEffect(() => {
250+
setName('test')
251+
}, [setName])
252+
return (
253+
<div>
254+
<div>count: {count}</div>
255+
<div>name: {name}</div>
256+
</div>
257+
)
258+
}
259+
260+
const { findByText } = render(<Component />)
261+
262+
await findByText('count: 42')
263+
await findByText('name: test')
264+
265+
expect(useStore.getState()).toEqual(
266+
expect.objectContaining({
267+
count: 42,
268+
name: 'test',
269+
})
270+
)
271+
})
272+
220273
it('can correclty handle a missing migrate function', async () => {
221274
console.error = jest.fn()
222275
const onRehydrateStorageSpy = jest.fn()

0 commit comments

Comments
 (0)