Quick Start
Installation
Bunshi is distributed on NPM as both a CommonJS and ES Module. It supports both JavaScript and TypeScript, and since it’s written in TypeScript it comes with type definitions and tests for typing out of the box.
npm i -D bunshi
Create a Molecule
Molecules are the core of bunshi. They are functions that return a value. Use molecules to create something
to share across your app. For this example, a jotai
atom.
import { molecule } from "bunshi";
import { atom } from "jotai/vanilla";
export const CountMolecule = molecule(() => atom(0));
When this
CountMolecule
is used it will always return the sameatom
. The value is memoized and cached so that it can be shared across an app.
Use a Molecule
To use a molecule, pass it to useMolecule
in your framework integration (React or Vue). An instance of atom
will be automatically created once
and shared across the application in every call to useMolecule
.
Scope a Molecule
Molecules can be scoped. Scoped molecules provide one value per scope, instead of one value globally.
In the above example the atom
was shared globally across the app, now let’s give each component it’s own state
using the built-in ComponentScope
.
import { ComponentScope, molecule, use } from "bunshi";
import { atom } from "jotai/vanilla";
export const CountMolecule = molecule(() => {
// Because scope is used here, this molecule is component scoped
use(ComponentScope);
return atom(0);
});
Scoping is declarative. By calling use(ComponentScope)
the molecule will automatically be scoped.
Important: See how the source for
Counter
didn’t change? This shows how Bunshi lets you pull state up, or push state down. No component changes needed, only molecule changes.
Use a custom scope
Sometimes state doesn’t need to be shared globally or per-component, but somewhere in the middle like a Form. Bunshi has createScope
for this.
There are many use cases for scopes; sharing data across pages, sections, forms, or even rows or columns in a table.
Here let’s share our state for all counters in the same form.
import { createScope, molecule, use } from "bunshi";
import { atom } from "jotai/vanilla";
// FormScope will be used for provided a string value to forms
export const FormScope = createScope("none");
export const CountMolecule = molecule(() => {
// Since scope is used here, it makes `CountMolecule` scoped to the form
use(FormScope);
return atom(0);
});
Provide a custom scope
Custom scopes need to be provided using the framework-specific API. Bunshi comes with integrations into React and Vue to provide scope implicitly.
For React use a ScopeProvider
as a wrapping component, and all children
can implicitly use that scope.
For Vue use provideScope
to provide scope implicitly to all children in
the slot
.
In this example everything inside of the <Form>
component will share an atom
, it won’t be unique per component
or shared across the entire application.
Conclusion - Decoupled and Lazy
The code that you wrote is decoupled and lazy.
- Decoupled: You can refactor the
CountMolecule
without affecting the thing that depend on it. - Lazy: An atom is only created lazily when it’s needed. It’s not eagerly created and sitting around in a global variable.
When your write code with molecules, you can pull state up or push state down, without having to refactor your components.
There are many other powerful features for molecules in Bunshi, such as:
- Molecules using other molecules
- Molecules using lifecycles to run code when they are first used (i.e. mounted or unmounted)
- Molecule interfaces for decoupling molecules
- Straightforward usage with many different state libraries