Update guides (#2474)

* Update guides

* Minor fixes

* Minor changes

* Update testing.md

Co-authored-by: Blazej Sewera <code@sewera.dev>

* Update testing.md

Co-authored-by: Blazej Sewera <code@sewera.dev>

---------

Co-authored-by: Blazej Sewera <code@sewera.dev>
This commit is contained in:
Danilo Britto 2024-04-15 20:56:39 -05:00 committed by GitHub
parent e00c69f82b
commit e8a5256548
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 61 additions and 34 deletions

View File

@ -107,12 +107,14 @@ Let's use the `createCounterStore` in our component and share it using a context
'use client' 'use client'
import { type ReactNode, createContext, useRef, useContext } from 'react' import { type ReactNode, createContext, useRef, useContext } from 'react'
import { type StoreApi, useStore } from 'zustand' import { useStore } from 'zustand'
import { type CounterStore, createCounterStore } from '@/stores/counter-store' import { type CounterStore, createCounterStore } from '@/stores/counter-store'
export const CounterStoreContext = createContext<StoreApi<CounterStore> | null>( export type CounterStoreApi = ReturnType<typeof createCounterStore>
null,
export const CounterStoreContext = createContext<CounterStoreApi | undefined>(
undefined,
) )
export interface CounterStoreProviderProps { export interface CounterStoreProviderProps {
@ -122,7 +124,7 @@ export interface CounterStoreProviderProps {
export const CounterStoreProvider = ({ export const CounterStoreProvider = ({
children, children,
}: CounterStoreProviderProps) => { }: CounterStoreProviderProps) => {
const storeRef = useRef<StoreApi<CounterStore>>() const storeRef = useRef<CounterStoreApi>()
if (!storeRef.current) { if (!storeRef.current) {
storeRef.current = createCounterStore() storeRef.current = createCounterStore()
} }
@ -194,7 +196,7 @@ export const createCounterStore = (
'use client' 'use client'
import { type ReactNode, createContext, useRef, useContext } from 'react' import { type ReactNode, createContext, useRef, useContext } from 'react'
import { type StoreApi, useStore } from 'zustand' import { useStore } from 'zustand'
import { import {
type CounterStore, type CounterStore,
@ -202,8 +204,10 @@ import {
initCounterStore, initCounterStore,
} from '@/stores/counter-store' } from '@/stores/counter-store'
export const CounterStoreContext = createContext<StoreApi<CounterStore> | null>( export type CounterStoreApi = ReturnType<typeof createCounterStore>
null,
export const CounterStoreContext = createContext<CounterStoreApi | undefined>(
undefined,
) )
export interface CounterStoreProviderProps { export interface CounterStoreProviderProps {
@ -213,7 +217,7 @@ export interface CounterStoreProviderProps {
export const CounterStoreProvider = ({ export const CounterStoreProvider = ({
children, children,
}: CounterStoreProviderProps) => { }: CounterStoreProviderProps) => {
const storeRef = useRef<StoreApi<CounterStore>>() const storeRef = useRef<CounterStoreApi>()
if (!storeRef.current) { if (!storeRef.current) {
storeRef.current = createCounterStore(initCounterStore()) storeRef.current = createCounterStore(initCounterStore())
} }

View File

@ -57,10 +57,25 @@ this means your application logic does not need to be changed or mocked when wri
The mock provided below will enable the relevant test runner to reset the zustand stores after each test. The mock provided below will enable the relevant test runner to reset the zustand stores after each test.
> **Warning:** In the following examples we are only supporting the curried version of create `(create()(...))`, ### Shared code just for testing purposes
> since it is supported on both JavaScript and TypeScript. If you are using the uncurried version of
> `create(...)` you will need to update your hooks to use the curried version, or update the mocks in order This shared code was added to avoid code duplication in our demo since we use the same counter store
> to support the uncurried version. creator for both implementations, with and without `Context` API — `createStore` and `create`, respectively.
```ts
// shared/counter-store-creator.ts
import { type StateCreator } from 'zustand'
export type CounterStore = {
count: number
inc: () => void
}
export const counterStoreCreator: StateCreator<CounterStore> = (set) => ({
count: 1,
inc: () => set((state) => ({ count: state.count + 1 })),
})
```
### Jest ### Jest
@ -126,7 +141,7 @@ afterEach(() => {
``` ```
```ts ```ts
// src/setup-jest.ts // setup-jest.ts
import '@testing-library/jest-dom' import '@testing-library/jest-dom'
``` ```
@ -137,7 +152,7 @@ import type { JestConfigWithTsJest } from 'ts-jest'
const config: JestConfigWithTsJest = { const config: JestConfigWithTsJest = {
preset: 'ts-jest', preset: 'ts-jest',
testEnvironment: 'jsdom', testEnvironment: 'jsdom',
setupFilesAfterEnv: ['./src/setup-jest.ts'], setupFilesAfterEnv: ['./setup-jest.ts'],
} }
export default config export default config
@ -218,7 +233,7 @@ afterEach(() => {
> to add `import { afterEach, vi } from 'vitest'` at the top. > to add `import { afterEach, vi } from 'vitest'` at the top.
```ts ```ts
// __mocks__/vitest-env.d.ts // global.d.ts
/// <reference types="vite/client" /> /// <reference types="vite/client" />
/// <reference types="vitest/globals" /> /// <reference types="vitest/globals" />
``` ```
@ -227,10 +242,10 @@ afterEach(() => {
> need to remove `/// <reference types="vitest/globals" />`. > need to remove `/// <reference types="vitest/globals" />`.
```ts ```ts
// src/setup-vitest.ts // setup-vitest.ts
import '@testing-library/jest-dom' import '@testing-library/jest-dom'
vi.mock('zustand') // to make it works like Jest (auto-mocking) vi.mock('zustand') // to make it work like Jest (auto-mocking)
``` ```
> **Note**: without [globals configuration](https://vitest.dev/config/#globals) enabled, we need > **Note**: without [globals configuration](https://vitest.dev/config/#globals) enabled, we need
@ -278,39 +293,47 @@ export const counterStoreCreator: StateCreator<CounterStore> = (set) => ({
// stores/user-counter-store.ts // stores/user-counter-store.ts
import { create } from 'zustand' import { create } from 'zustand'
import { type CounterStore, counterStoreCreator } from './counter-store-creator' import {
type CounterStore,
counterStoreCreator,
} from '../shared/counter-store-creator'
export const useCounterStore = create<CounterStore>()(counterStoreCreator) export const useCounterStore = create<CounterStore>()(counterStoreCreator)
``` ```
```tsx ```tsx
// stores/use-counter-store-context.tsx // contexts/use-counter-store-context.tsx
import { import { type ReactNode, createContext, useContext, useRef } from 'react'
type PropsWithChildren, import { createStore } from 'zustand'
createContext,
useContext,
useRef,
} from 'react'
import { type StoreApi, createStore } from 'zustand'
import { useStoreWithEqualityFn } from 'zustand/traditional' import { useStoreWithEqualityFn } from 'zustand/traditional'
import { shallow } from 'zustand/shallow' import { shallow } from 'zustand/shallow'
import { type CounterStore, counterStoreCreator } from './counter-store-creator' import {
type CounterStore,
counterStoreCreator,
} from '../shared/counter-store-creator'
export const createCounterStore = () => { export const createCounterStore = () => {
return createStore<CounterStore>(counterStoreCreator) return createStore<CounterStore>(counterStoreCreator)
} }
export const CounterStoreContext = createContext<StoreApi<CounterStore>>( export type CounterStoreApi = ReturnType<typeof createCounterStore>
null as never,
export const CounterStoreContext = createContext<CounterStoreApi | undefined>(
undefined,
) )
export type CounterStoreProviderProps = PropsWithChildren export interface CounterStoreProviderProps {
children: ReactNode
}
export const CounterStoreProvider = ({ export const CounterStoreProvider = ({
children, children,
}: CounterStoreProviderProps) => { }: CounterStoreProviderProps) => {
const counterStoreRef = useRef(createCounterStore()) const counterStoreRef = useRef<CounterStoreApi>()
if (!counterStoreRef.current) {
counterStoreRef.current = createCounterStore()
}
return ( return (
<CounterStoreContext.Provider value={counterStoreRef.current}> <CounterStoreContext.Provider value={counterStoreRef.current}>
@ -400,7 +423,7 @@ const renderCounter = () => {
import { import {
CounterStoreProvider, CounterStoreProvider,
useCounterStoreContext, useCounterStoreContext,
} from '../../stores/use-counter-store-context' } from '../../contexts/use-counter-store-context'
const Counter = () => { const Counter = () => {
const { count, inc } = useCounterStoreContext((state) => state) const { count, inc } = useCounterStoreContext((state) => state)
@ -470,8 +493,8 @@ const renderCounterWithContext = () => {
**CodeSandbox Demos** **CodeSandbox Demos**
- Jest Demo: https://codesandbox.io/p/sandbox/zustand-jest-demo-twkypn - Jest Demo: https://stackblitz.com/edit/jest-zustand
- Vitest Demo: https://codesandbox.io/p/sandbox/zustand-vitest-demo-ph5gnj - Vitest Demo: https://stackblitz.com/edit/vitest-zustand
## References ## References