Using middlewares

By default, a zustand store only lets you get and set data. As soon as you'll want it to do more (persist data, log updates, subscribe to changes, etc) is when zustand middlewares will come into play. zfy offers 2 types of middleware for that purpose: built-in and custom.

Built-in

Out of the box, you have access to a persist, log and subscribe middlewares. There's not much you'll need to do here as these middlewares can be configured directly in createStore(). You can use none, one or all of them at once:

import AsyncStorage from '@react-native-async-storage/async-storage'
import { createStore } from '@colorfy-software/zfy'

const data = { name: 'zfy' }

type StoreDataType = typeof data

const store = createStore<StoreDataType>('store', data, {
  persist: { getStorage: () => AsyncStorage },
  subscribe: true,
  log: true,
})

const listener = (newName, oldName) => console.log({ newName, oldName })

const unsubscribe = store.subscribeWithSelector?.(
  state => state.data.name,
  listener,
  { fireImmediately: true }
)

Here, in just 3 lines, you've enabled zustand's own persist & subscribeWithSelector middlewares, on top of zfy's log middleware.

  • The log middleware will print the store name, previous state, payload data and new state upon each update.

  • You can refer to zustand's documentation for details about persist & subscribeWithSelector middlewares.

Custom

At some point, your use cases might require more than what the 3 built-in middlewares can offer. It could be that you want to use another of zustand's middleware or even plug in your very own custom middleware. zfy allows you to do so via the customMiddlewares option:

import { devtools } from 'zustand/middleware'
import { ZfyMiddlewareType, createStore } from '@colorfy-software/zfy'

const data = { name: 'zfy' }

type StoreDataType = typeof data

const customMiddleware: ZfyMiddlewareType<StoreDataType> =
  (storeName, config) => (set, get, api) =>
    config(
      (args) => {
        // 📍Do anything in your middlware
        set(args)
        console.log(storeName)
      },
      get,
      api
    )

const zustandMiddleware: ZfyMiddlewareType<StoreDataType> = (storeName, config) =>
  devtools((set, get, api) => config(set, get, api), { name: storeName })

const store = createStore('store', data, {
  customMiddlewares: [customMiddleware, zustandMiddleware],
})

This snippet is only provided as an example to show you how to integrate a zustand middleware. You shouldn't rely on devtools as zfy uses Immer instead of Redux-like actions & dispatchers.

You'll notice that zfy's middlewares look a tiny bit different from zustand's. Instead of only config as in the initial function argument, you also receive thestoreName (the one you provided as createStore()first argument). This can be very useful if you want to have conditional logic in your middleware based on which store is using it for instance.

Last updated