From b703491de0d9978dacb6c50461cf570ca3f4d61e Mon Sep 17 00:00:00 2001 From: Holger Grosse-Plankermann Date: Mon, 23 Jan 2023 08:24:27 +0100 Subject: [PATCH 1/3] Docs for discussion 1564 --- docs/guides/typescript.md | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/guides/typescript.md b/docs/guides/typescript.md index a16ad3f8c5..d192e55ebc 100644 --- a/docs/guides/typescript.md +++ b/docs/guides/typescript.md @@ -399,6 +399,59 @@ A detailed explanation on the slices pattern can be found [here](./slices-patter If you have some middlewares then replace `StateCreator` with `StateCreator`. For example, if you are using `devtools` then it will be `StateCreator`. See the ["Middlewares and their mutators reference"](#middlewares-and-their-mutators-reference) section for a list of all mutators. +### Using a vanilla store as a bound store +Create your vanilla store: +```ts +import { createStore } from "zustand/vanilla"; + +interface BearState { + bears: number + increase: (by: number) => void +} + +const initialBearState = { bears: 0 }; +export const vanillaBearStore = createStore((set, getState) => ({ + ...initialBearState, + increase: (by) => set((state) => ({ bears: state.bears + by })) +})); +``` +Create a hook to provide a bound store to be used in your component: +```ts +import { useStore } from "zustand"; + +export const useBoundBearStore = ( + selector: (state: BearState) => T = (state) => state as T, + equals?: (a: T, b: T) => boolean +) => useStore(vanillaBearStore, selector, equals); +``` +Now you can access your vanilla store (e.g. in your tests) like: +```ts +import { bearStore, initialBearStore } from "./BearStore"; + +describe("MyComponent should", () => { + // remember to reset the store + beforeEach(() => { + bearStore.setState(initialState); + }); + + it("set the value", () => { + const store = fooStore; + // do the test + expect(store.getState().bears).toEqual(0); + }); +}); +``` +And access the store in your component +```tsx +import { useBoundBearStore } from "./BearStore"; + +export const BearComponent = () => { + const bears = useBoundBearStore((state) => state.bears); + + return
{ bears }
; +}; +``` + ## Middlewares and their mutators reference - `devtools` — `["zustand/devtools", never]` From bb2b3b3fcfc9ec18cb40034b502e1fad30dec34a Mon Sep 17 00:00:00 2001 From: Holger Grosse-Plankermann Date: Mon, 23 Jan 2023 10:58:55 +0100 Subject: [PATCH 2/3] Apply prettier --- docs/guides/typescript.md | 48 +++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/docs/guides/typescript.md b/docs/guides/typescript.md index d192e55ebc..0c8f67e211 100644 --- a/docs/guides/typescript.md +++ b/docs/guides/typescript.md @@ -400,56 +400,64 @@ A detailed explanation on the slices pattern can be found [here](./slices-patter If you have some middlewares then replace `StateCreator` with `StateCreator`. For example, if you are using `devtools` then it will be `StateCreator`. See the ["Middlewares and their mutators reference"](#middlewares-and-their-mutators-reference) section for a list of all mutators. ### Using a vanilla store as a bound store + Create your vanilla store: + ```ts -import { createStore } from "zustand/vanilla"; +import { createStore } from 'zustand/vanilla' interface BearState { bears: number increase: (by: number) => void } -const initialBearState = { bears: 0 }; +const initialBearState = { bears: 0 } export const vanillaBearStore = createStore((set, getState) => ({ ...initialBearState, - increase: (by) => set((state) => ({ bears: state.bears + by })) -})); + increase: (by) => set((state) => ({ bears: state.bears + by })), +})) ``` + Create a hook to provide a bound store to be used in your component: + ```ts -import { useStore } from "zustand"; +import { useStore } from 'zustand' export const useBoundBearStore = ( selector: (state: BearState) => T = (state) => state as T, equals?: (a: T, b: T) => boolean -) => useStore(vanillaBearStore, selector, equals); +) => useStore(vanillaBearStore, selector, equals) ``` + Now you can access your vanilla store (e.g. in your tests) like: + ```ts -import { bearStore, initialBearStore } from "./BearStore"; +import { bearStore, initialBearStore } from './BearStore' -describe("MyComponent should", () => { - // remember to reset the store +describe('MyComponent should', () => { + // remember to reset the store beforeEach(() => { - bearStore.setState(initialState); - }); + bearStore.setState(initialState) + }) - it("set the value", () => { - const store = fooStore; + it('set the value', () => { + const store = fooStore // do the test - expect(store.getState().bears).toEqual(0); - }); -}); + expect(store.getState().bears).toEqual(0) + }) +}) ``` + And access the store in your component + ```tsx -import { useBoundBearStore } from "./BearStore"; +import { useBoundBearStore } from './BearStore' export const BearComponent = () => { - const bears = useBoundBearStore((state) => state.bears); + const bears = useBoundBearStore((state) => state.bears) - return
{ bears }
; -}; + return
{bears}
+} ``` ## Middlewares and their mutators reference From 48af612a25a92d2e26dafbb92f0b75e12fc9ae50 Mon Sep 17 00:00:00 2001 From: Holger Grosse-Plankermann Date: Tue, 24 Jan 2023 20:20:35 +0100 Subject: [PATCH 3/3] fix(docs/typescript): use overloading example discussed in #1564 --- docs/guides/typescript.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/guides/typescript.md b/docs/guides/typescript.md index 0c8f67e211..95e7be6654 100644 --- a/docs/guides/typescript.md +++ b/docs/guides/typescript.md @@ -411,7 +411,7 @@ interface BearState { increase: (by: number) => void } -const initialBearState = { bears: 0 } +export const initialBearState = { bears: 0 } export const vanillaBearStore = createStore((set, getState) => ({ ...initialBearState, increase: (by) => set((state) => ({ bears: state.bears + by })), @@ -423,25 +423,32 @@ Create a hook to provide a bound store to be used in your component: ```ts import { useStore } from 'zustand' -export const useBoundBearStore = ( - selector: (state: BearState) => T = (state) => state as T, +export function useBoundBearStore(): BearState +export function useBoundBearStore( + selector: (state: BearState) => T, equals?: (a: T, b: T) => boolean -) => useStore(vanillaBearStore, selector, equals) +): T +export function useBoundBearStore(selector?: any, equals?: any) { + return useStore(vanillaBearStore, selector, equals) +} ``` +> **_NOTE:_** We prefer function overloading here, as this closely follows the definition of `useStore` itself. +> If you are not familiar with this pattern, just have a look here: [Typescript Docs](https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads) + Now you can access your vanilla store (e.g. in your tests) like: ```ts -import { bearStore, initialBearStore } from './BearStore' +import { vanillaBearStore, initialBearState } from './BearStore' describe('MyComponent should', () => { // remember to reset the store beforeEach(() => { - bearStore.setState(initialState) + vanillaBearStore.setState(initialState) }) it('set the value', () => { - const store = fooStore + const store = vanillaBearStore // do the test expect(store.getState().bears).toEqual(0) })