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' }); // ✅
...
}