Zustand Store

Armedi • 2022-05-17

Problems with existing state management and the solution.

background

Problem

We have deeply nested context for data. This cause several problems:

  • Using context for frequently changing data triggers unnecessary rerenders of components
  • Using context for state tightly couple data with React. This makes it impossible to deal with data outside of React component tree.

Using Zustand for State Management

Zustand is chosen for state management because it is simple, easy to use, and already used internally by Plate.

Store Structure

Currently the store is structured as follows:

interface RootSlice {  tokenHandlers: {    spacePermissionTokenHandler: PermissionTokenHandler    subscriptionTokenHandler: SubscriptionTokenHandler  }	spaces: { [spaceID: string]: ISpace } | null  queryStates: QueryStates	// actions  listSpaces(): Promise<void>  getSpace(spaceID: string): Promise<void>}

To use the store

const spaces = useStore(state => state.spaces)

You can look further at zustand documentation on how to use it https://github.com/pmndrs/zustand

Fetching States

Because most of the data come from server asynchronously, sometimes you need to check the status and error. That’s what queryStates is for.

The shape of QueryStates is as follow

type QueryStates = {  [key: string]: QueryState}type QueryState<T> = {  data?: T | null  status: 'idle' | 'loading' | 'error' | 'success' | 'stale'  error: string  isIdle: boolean  isLoading: boolean  isError: boolean  isSuccess: boolean  isStale: boolean}

Each data point is identified with a string key. You don't read it directly, but use getQueryState function or useStoreQuery hook for type-safety and nice autocompletion from VSCode

const {data, isLoading, isError} = useStoreQuery('listPages', [])

Using this hook will allow automatic fetching of data if they are not fetched yet. You can disable the automatic fetching by providing options as third param

const {data, isLoading, isError} = useStoreQuery('listPages', [], { autoFetch: false })

Most of the time you will only need to use the custom hooks useSpaces , useSpace , etc

const {data, isLoading, isError} = useSpaces()

The API is inspired by react-query library

So why not using react-query?

  1. Because react-query couples the data with UI. There are places where its better to deal with data outside of react component tree, like the data sync with server (currently triggered in 10s interval). Doing every data manipulations inside React makes codes messy. It is possible to use react-query separately from react using its core, but the usage is mostly undocumented.
  2. We don’t need advance caching feature of react-query.


See More Posts


Cardy

Copyright © 2021 Govest, Inc. All rights reserved.