Skip to main content
React provides the context API for handling state globally in your application. While it’s not bad in its own right, it requires a ton of boilerplate and maintaining a different context provider for each feature subset quickly gets out of hand in slightly bigger applications Hana Store solves this issue by providing a one-line way to interact with the context API so you don’t have to create all the boilerplate required to store and get items in your apps.
Hana Store is automatically added to projects generated using create-hana-app, but if you already have a React or React Native project, you can install and use it instantlyInstall from npm
npm install @hanabira/store

Using your store

Hana store uses a very similar syntax to React’s built-in useState() which allows you to read & write from the same hook. The useStore() hook takes in the name of the item in the store you want to use, and returns a setter/getter for it.
import { useStore } from '@hanabira/store';

...

const [item, setItem] = useStore('item');

return (
  <div>
    <p>Value: {item}</p>
    <button onClick={() => setItem('New value')}>Set Item</button>
  </div>
);
Although Hana Store requires no setup, it allows you to customize it with some pretty cool updates

Store Initialization

Hana allows you to initialize your store with your own configuration which allows you to do things like setting an initial state, use state modules, sync to an external storage like localStorage or Async Storage, and so much more
src/pages/_app.tsx
import { createStore } from '@hanabira/store';

const store = createStore({
  state: {
    item: 'Initial value',
  },
  reducers: {
    setItem: (state, payload) => ({ ...state, item: payload }),
  },
  compareState: true,
  plugins: [],
});

...

// your app here
The state key allows you to initialize your store with default values which will be returned on the initial load instead of null . This is especially useful when using TypeScript so you can prevent redundant null checks and avoid using ?.
You should only use createStore()once in your application, and in a root component like the _app or similar

Syncing to external storage

It’s very common to persist your state to an external or on-device storage, which allows you to maintain the application’s state even when the application is closed or device is restarted. This usually require’s annoying boilerplate or using an effect to watch states which run quite ineffeciently. Hana’s solution to this problem is a built-in store plugin that automatically syncs your global state to the browser’s localStorage or any other storage of your choice if specified
import { PersistedState, createStore } from '@hanabira/store';

createStore({
  plugins: [PersistedState],
});
You can pass some extra config to the PersistedState
import { PersistedState, createStore } from '@hanabira/store';
import AsyncStorage from '@react-native-async-storage/async-storage';

createStore({
  plugins: [
    new PersistedState({
      storage: AsyncStorage,
      env: 'react-native',
    }),
  ],
});
  • The env property is used to tell the plugin that it is running in a React Native environment. This is important because React Native does not have a window object. If you do not pass this property, the plugin will assume that it is running in a browser environment.
  • The storage property is used to tell the plugin which storage medium to use. This property can be any object that implements the Storage interface. This includes localStorage, sessionStorage, and AsyncStorage from React Native.
  • It also supports a key property which is used to specify the key to use when saving the state. This defaults to hana-store.
createStore({
  plugins: [
    new PersistedState({
      key: 'my-app-store',
    }),
  ],
});
  • There is also an exclude property is an array of keys that should not be persisted. This is useful for excluding sensitive data like passwords and tokens from being persisted. If a value is excluded, it will not be persisted, but it will still be available in the state object.
createStore({
  plugins: [
    new PersistedState({
      exclude: ['password', 'token'],
    }),
  ],
});
  • The include property is an array of keys that should be persisted. This is useful for persisting only certain values in the state object. If the include property is set, the exclude property will be ignored and only the values in the include property will be persisted.
createStore({
  plugins: [
    new PersistedState({
      include: ['user'],
    }),
  ],
});