Docs
Stores
Stores Introduction

Stores

The concept is same as store, but this can be used for multiple stores.

Create a Stores

import { createStores } from 'floppy-disk';
 
type CatStoreKey = { catId: number };
type CatStore = { age: number; isSleeping: boolean; increaseAge: () => void; reset: () => void };
 
const useCatStores = createStores<CatStoreKey, CatStore>(
  ({ set, get, key }) => ({
    //         ^store key
    age: 0,
    isSleeping: false,
    increaseAge: () => set((state) => ({ age: state.age + 1 })),
    reset: () => set({ age: 0, isSleeping: false }),
  })
);

Using a Stores as Hook

We need to specify the store key (an object) as identifier.

function CatPage() {
  const [catId, setCatId] = useState(1);
 
  return (
    <>
      <div>Current cat id: {catId}</div>
      <button onClick={() => setCatId((prev) => prev - 1)}>Prev cat</button>
      <button onClick={() => setCatId((prev) => prev + 1)}>Next cat</button>
 
      <Cat catId={catId} />
      <Control catId={catId} />
    </>
  );
}
 
function Cat({ catId }) {
  const { age } = useCatStores({ catId });
  return <div>Cat's age: {age}</div>;
}
 
function Control({ catId }) {
  const { increaseAge } = useCatStores(
    { catId },
    (state) => [state.increaseAge]
  );
  return <button onClick={increaseAge}>Increase cat's age</button>;
}

Using Store Outside Component

Reading/writing state and reacting to changes outside of components.

const alertCatAge = () => {
  alert(useCatStore.get({ catId: 3 }).age);
  //                      ^ get cat store with catId: 3
};
 
const toggleIsSleeping = () => {
  useCatStore.set({ catId: 7 }, (state) => ({ isSleeping: !state.isSleeping }));
  //                ^ get cat store with catId: 7
};
 
const unsub = useCatStore.subscribe(
  { catId: 9 },
  (state) => {
    console.log('The value of age for catId 9 is changed!', state.age);
  },
  (state) => [state.age],
);

Stores Methods

Stores method is a way to do something with the store outside of a component like what we've learned before.

import { createStore, createStores } from 'floppy-disk';
 
type State = { age: number }
const useCatStore  = createStore<State>(() => ({ age: 0 }));
const useFoxStores = createStores<{ id: string }, State>(() => ({ age: 0 }));
 
const getCatAge = () => useCatStore.get().age;
const getFoxAge = ({ id }) => useFoxStore.get({ id }).age;
 
const resetCatAge = () => useCatStore.set({ age: 0 });
const resetFoxAge = ({ id }) => useFoxStore.set({ id }, { age: 0 });
 
const subscribeCat = () => useCatStore.subscribe(console.log);
const subscribeFox = ({ id }) => useFoxStore.subscribe({ id }, console.log);
 
const getSubscribersOfCat = () => useCatStore.getSubscribers();
const getSubscribersOfFox = ({ id }) => useFoxStore.getSubscribers({ id });

Stores-only (not available in createStore) methods:

useCatStores.getAll();
// Returns array of store state
 
useCatStores.getAllWithSubscriber();
// Returns array of store state, but only for stores with subscribers

Store Key

When using stores, the store key is a store identifier. It should be an object. The default hashing mechanism is by sorting the object keys and stringify it. And of course we can customize it using hashKeyFn option.

import {
  createStores,
  hashStoreKey, // Default hash function
} from 'floppy-disk';
 
const useProductStores = createStores(
  ({ get, set, key, keyHash }) => {
    console.log(key, keyHash); // Check key (object) and keyHash (string)
    return {
      data: null,
    };
  },
  {
    hashKeyFn: myCustomHashFn, // Customize here
  },
);
 
useProductStores({ keyword: 'floppy' });
// Hash: '{"id":"floppy"}'
 
useProductStores({ keyword: 'floppy', sort: 'asc' });
// Hash: '{"id":"floppy","sort":"asc"}'
 
useProductStores({ sort: 'asc', keyword: 'floppy' });
// Hash: '{"id":"floppy","sort":"asc"}'

If the hashed store key is same, it will use the same stored state.

Note that we don't need to memoize the store key / query key.

function Component() {
  const storeKey = useMemo(() => ({ keyword: 'floppy' }), []); // ❌
  const storeData = useProductStores(storeKey); // ❌
  const storeData = useProductStores({ keyword: 'floppy' }); // ✅
 
  const queryKey = useMemo(() => ({ generation: 'ii', sort: 'asc' }), []); // ❌
  const { isLoading, data } = usePokemonsQuery(queryKey); // ❌
  const { isLoading, data } = usePokemonsQuery({ generation: 'ii', sort: 'asc' }); // ✅
  ...
}