Docs
Store
Store Introduction

Store

Create a Store

import { createStore } from 'floppy-disk';
 
type CatStore = {
  age: number;
  isSleeping: boolean;
  increaseAge: () => void;
  reset: () => void;
};
 
const useCatStore = createStore<CatStore>(({ set }) => ({
  age: 0,
  isSleeping: false,
  increaseAge: () => set((state) => ({ age: state.age + 1 })),
  reset: () => set({ age: 0, isSleeping: false }),
}));

Use the Hook Anywhere

No providers are needed.

function Cat() {
  const age = useCatStore('age');
  return <div>Cat's age: {age}</div>;
}
 
function Control() {
  const increaseAge = useCatStore('increaseAge');
  return <button onClick={increaseAge}>Increase cat's age</button>;
}

Control the Reactivity

The concept is same as useEffect dependency array.

function Cat() {
  const { age, isSleeping } = useCatStore();
  // Will re-render every state change    ^
}
 
function Cat() {
  const { age, isSleeping } = useCatStore((state) => [state.isSleeping]);
  // Will only re-render when isSleeping is updated   ^
  // Update on age won't cause re-render this component
}
 
function Cat() {
  const { age, isSleeping } = useCatStore((state) => [state.age, state.isSleeping]);
  // Will re-render when age or isSleeping is updated ^
}
 
function Cat() {
  const { age, isSleeping } = useCatStore((state) => [state.age > 3]);
  // Will only re-render when (age>3) is updated
}

Even simpler way, after version 2.13.0, we can use store's object key:

function YourComponent() {
  const age = useCatStore('age');
  // Will only re-render when age is updated
}
 
function YourComponent() {
  const age = useCatStore('isSleeping');
  // Will only re-render when isSleeping is updated
}

Set Default Reactivity

const useCatStore = createStore(
  ({ set }) => ({
    age: 0,
    isSleeping: false,
    increaseAge: () => set((state) => ({ age: state.age + 1 })),
    reset: () => set({ age: 0, isSleeping: false }),
  }),
  {
    defaultDeps: (state) => [state.age],
  },
);
 
function Cat() {
  const { age } = useCatStore();
  //                          ^will only re-render when age changed
  return <div>Cat's age: {age}</div>;
}

Using Store Outside Component

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

const alertCatAge = () => {
  alert(useCatStore.get().age);
};
 
const toggleIsSleeping = () => {
  useCatStore.set((state) => ({ isSleeping: !state.isSleeping }));
};
 
const unsub = useCatStore.subscribe(
  // Action
  (state) => {
    console.log('The value of age is changed!', state.age);
  },
  // Reactivity dependency (just like useEffect dependency mentioned above)
  (state) => [state.age],
  // ^If not set, the action will be triggered on every state change
);
 
const getSubscribersOfCat = () => useCatStore.getSubscribers();

Important Notes

Don't mutate.

import { createStore } from 'floppy-disk';
 
const useCartStore = createStore(({ set, get }) => ({
  products: [],
  addProduct: (newProduct) => {
    const currentProducts = get().products;
    product.push(newProduct); // ❌ Don't mutate
    set({ product });
  },
}));

Don't use conditional reactivity selector.

function Cat({ isSomething }) {
  const value = useCatStore(isSomething ? 'age' : 'isSleeping'); // ❌
  const { age } = useCatStore(isSomething ? (state) => [state.age] : null); // ❌
  const { age } = useCatStore((state) => (isSomething ? [state.age] : [state.isSleeping])); // ❌
  ...
}

No need to memoize the reactivity selector.

function Cat() {
  const selectAge = useCallback((state) => [state.age], []); // ❌
  const { age } = useCatStore(selectAge);
  ...
}