Skip to content

Immutable state store for react apps with suspense integration.

License

Notifications You must be signed in to change notification settings

michael-klein/forimmer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

forimmer build status npm types

Immutable state store for react apps with suspense integration.

What is this?

forimmer is a experimental functional state store for react apps, which uses immer for immutability and integrates with the new react suspense API. It was in part inspired by the excellent pullstate.

The name is just a silly play with words. "immer" means "always" or "ever" in German and "für immer" means "forever". So, forimmer is basically just a fun, bad translation (that you might encounter from actual Germans trying to speak English). I'm not good at naming things.

How does it work?

First, here is a codesandbox with a very contrived example: link

You can install forimmer from npm:

npm install forimmer -s

Creating a store

A new store is created with the createStore function:

import { createStore } from "forimmer";

const store = createStore<{
  foo: string;
  bar: string;
}>();

You can also supply an initial state:

import { createStore } from "forimmer";

const store = createStore<{
  foo: string;
  bar: string;
}>({foo: "foo"});

If your initial state covers the entire desired State interface, you may omit the generics and createStore will infer the type of your state:

import { createStore } from "forimmer";

const store = createStore({foo: "foo", bar: "bar"});

Using the store state in your react app:

If you just want to access the current state of the store, use:

const state = store.getCurrentState();

The useStoreState hooks allows you to pick values from the store (returning them in an array) and subscribe to changes thereof:

function SomeComponent() {
  const [foo] = useStoreState(store, state => [state.foo]); // useStoreState will infer the type of foo
  return <div>{foo}</div>
}

Whenever state.foo changes (and not any other value), the component will re-render and foo will be updated to the new value.

Suspense integration

If any of the values returned from useStoreState is undefined OR if trying to access a value deeper in the state tree would throw an error, useStoreState will throw a Promise which resolves once the store has been updated and the desired values become available.

You can wrap your component in React.Suspense to show a fallback UI that will automatically appear when useStoreState throws and the loading Promise is pending:

function ComponentWithSuspense() {
  return <React.Suspense fallback={<div>...loading foo</div>}>
    <SomeComponent />
  </React.Suspense>
}

Modifying the store state with actions

In order to modify the store state, you can define store actions. A store action is an async function (that might for instance fetch data from an API) which returns a state recipe, which in turn is a function which is passed a draft state to modify (see the immer docs):

// this will create a store action with a payload:
const setFoo = store.createStoreAction(
  async (newFoo: string) => draft => {
    draft.foo = newFoo;
  }
);

setFoo("foo") // set store.foo to "foo"

const fetchFoo = store.createStoreAction(
  async () => {
    const foo:string = await someApiCall();
    return draft => {
      draft.foo = newFoo;
    }
  }
);
fetchFoo() // fetch foo from some api

About

Immutable state store for react apps with suspense integration.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published