Persisting & rehydrating data

Previous versions of zfy used to rely on a custom persistence solution. Fortunately, zustand added built-in support for this feature in v3.1.4. Therefore: zfy simply employs zustand's persist middleware and tries to offer an easier API to use.

Refer to the CreateStoreOptionsType.persistto read the full API reference.

Persistence

Data is persisted on a store to store basis. In order to make a store persist its data, you need to provide the persist option to createStore() 3rd argument and specify which storage solution you'd like to use:

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

import type { StoresDataType } from '../types'

export const initialState: StoresDataType['user'] = {
  id: '',
  likes: 0,
}

export default createStore<StoresDataType['user']>('user', initialState, {
  persist: { getStorage: () => AsyncStorage },
})

This means that you can have stores using different storage solutions depending on your use case (LocalStorage, Cookies, IndexedDB, etc).

If you want to look into how to bundle stores by type of storage solutions used, for instance, refer to the Handling multiple stores guide.

You need to make sure that your storage solution provides agetItem(), asetItem() and aremoveItem()(only needed for zustand v4).

If it does not, of course, you can always provide it yourself:

import { MMKV } from 'react-native-mmkv'
import { createStore } from '@colorfy-software/zfy'

import type { StoresDataType } from '../types'

export const initialState: StoresDataType['user'] = {
  id: '',
  likes: 0,
}

export const storage = new MMKV({ id: 'user' })

export default createStore<StoresDataType['user']>('user', initialState, {
  persist: {
    getStorage: () => ({
      getItem: (name) => storage.getString(name) ?? null,
      setItem: (name, value) => storage.set(name, value),
      removeItem: (name) => storage.delete(name),
    }),
  },
})

From there you're all set. Just use getState().update() to update your store as covered in the Creating & using a store guide and your data will be persisted.

Rehydration

Similarly to the persistence solution, zfy directly uses zustand's rehydration under the hood and simply exposes it via a different (hopefully simpler) API.

Usually, when it comes to rehydration, you might want to hide all (or part) of your app while the necessary stores are rehydrating. zfy provides 2 solutions out of the box to do so: a component - <PersistGate/> - and a React Hook, useRehydrate().

<PersistGate />

This component expects an array of stores and will take care of displaying its children only when all the stores will have been rehydrated. You can as well provide a loader if needed:

src/App.tsx
import { SafeAreaView, Text } from 'react-native'
import { PersistGate } from '@colorfy-software/zfy'

import appStore from './stores/app-store'
import userStore from './stores/user-store'

const Loader = () => (
  <SafeAreaView>
    <Text>ā³ Loading...</Text>
  </SafeAreaView>
)

export default function App() {
  return (
    <PersistGate stores={[appStore, userStore]} loader={<Loader />}>
      <MyApp />
    </PersistGate>
  )
}

Note that if you add stores in thestores array that do not have thepersist middleware enabled,<PersistGate/>(as well as useRehydrate())will automatically skip them.

useRehydrate()

If <PersistGate /> doesn't fit your need, you can have finer control over what happens via useRehydrate():

src/App.tsx
import { useEffect } from 'react'
import { SafeAreaView, Text } from 'react-native'
import { useRehydrate } from '@colorfy-software/zfy'

import appStore from './stores/app-store'
import userStore from './stores/user-store'

const Loader = () => (
  <SafeAreaView>
    <Text>Loading...</Text>
  </SafeAreaView>
)

export default function App() {
  const isRehydrated = useRehydrate([appStore, userStore])

  useEffect(() => {
    if (isRehydrated) {
      // šŸ“ Trigger side effect upon rehydration?
    }
  }, [isRehydrated])

  return isRehydrated ? <Loader /> : <MyApp />
}

If you want to rehydrate/check the rehydration status of a given store directly, please refer to the corresponding section of the zustand's documentation:

Last updated