Fork of fattafatta/rescript-jotai
The ReScript ecosystem is in flux right now as React@18 and ReScript@10 are slowly making their way across the ecosystem. Instead of introducing these rather big changes upstream now, I'm maintaining a fork to allow the ecosystem to catch up so that the changes needed are a much smaller delta.
ReScript bindings for Jotai. Primitive and flexible state management for React.
Install with npm
:
npm install jotai @scotttrinh/rescript-jotai
Or install with yarn
:
yarn add jotai @scotttrinh/rescript-jotai
Add @scotttrinh/rescript-jotai
as a dependency to your bsconfig.json
:
"bs-dependencies": ["@rescript/react", "@scotttrinh/rescript-jotai"]
A Provider works just like React context provider. If you don't use a Provider, it works as provider-less mode with a default store. A Provider will be necessary if we need to hold different atom values for different component trees.
module App = {
@react.component
let make = () =>
<Jotai.Provider>
...
</Jotai.Provider>
}
Atoms have a value, a setter function (from Atom.Actions
), and a set of tags that restrict which operations are allowed on the atom (e.g is the atom #resettable
).
Normally the type will be inferred automatically. If annotation is required it should be sufficient to provide the first type (the value).
Example:
let atom: Jotai.Atom.t<int, _, _> = Jotai.Atom.make(1)
Create a (primitive) readable and writable atom.
let atom1 = Jotai.Atom.make(1)
let atom2 = Jotai.Atom.make('text')
Create a computed readonly atom. A computed atom can combine any number of readable atoms to create a single derived value. The syntax varies slightly from Jotai.
Note the curly braces in ({get})
.
let atom1 = Jotai.Atom.make(1)
let atom2 = Jotai.Atom.makeComputed(({get}) => get(atom1) + 1)
let atom3 = Jotai.Atom.makeComputed(({get}) => get(atom1) + get(atom2) + 1)
(Requires React.Suspense) Create an computed readonly atom with an async getter. All components will be notified when the returned promise resolves.
let atom1 = Jotai.Atom.make(1)
let atom2 = Jotai.Atom.makeComputedAsync(({get}) => {
Js.Promise.make((~resolve, ~reject as _) => {
let count = atom1->get + 1
Js.Global.setTimeout(() => resolve(. count), 100)->ignore
})
})
Create a computed atom that supports read and write.
let atom1 = Jotai.Atom.make(1)
let atom2 = Jotai.Atom.makeWritableComputed(
({get}) => get(atom1) + 1,
({get, set}, arg) => {
atom1->set(get(atom1) + arg)
},
)
Create a computed atom with asynchronous write. Jotai supports async write operations for computed atoms. Simply call 'set' when the promise resolves.
let atom1 = Jotai.Atom.make(1)
let atom2 = Jotai.Atom.makeWritableComputedAsync(
({get}) => get(atom1) + 1,
({get, set}, arg) => {
Js.Promise.make((~resolve, ~reject as _) => {
let count = get(atom1) + arg
Js.Global.setTimeout(() => resolve(. count), 100)->ignore
})->Js.Promise.then_(value => {
atom1->set(value)
Js.Promise.resolve()
}, _)
},
)
Create a writeOnly computed atom.(Note: Sometimes the type can not be inferred and has to be annotated)
let atom1 = make(1)
let atom2: Jotai.Atom.t<int, _, _> = Jotai.Atom.makeWriteOnlyComputed(({get, set}, args) =>
atom1->set(get(atom1) + args)
)
The onMount
function will be invoked when the atom is first used in a provider,
and onUnmount
will be invoked when it's not used.
let atom1 = Jotai.Atom.make(1)
atom1->Jotai.Atom.onMount(setAtom => {
setAtom(a => a + 1) // increment count on mount
() => () // return onUnmount function
})
Standard hook to use with read/write atoms.
(For handling of readOnly/writeOnly atoms see Jotai.Utils
)
let atom1 = Jotai.Atom.make(1)
let (value, setValue) = Jotai.Atom.use(atom1)
Creates an atom with a value persisted in localStorage
Currently only localStorage
is supported.
let atom1 = Jotai.Utils.AtomWithStorage.make('storageKey', 1)
Creates an atom that can be resetted to its initialValue with the useResetAtom
hook.
let atom = Jotai.Utils.AtomWithReset.make(1)
// ... change value ...
let reset = Jotai.Utils.useResetAtom(atom)
reset()
Create a resettable primitive atom. Its default value can be specified with a read function instead of a static initial value.
let atom1 = Jotai.Atom.make(1)
let atom2 = Jotai.Utils.AtomWithDefault.make(({get}) => atom1->get + 1)
Creates an atom that uses a reducer to update its value.
type actionType = Inc(int) | Dec(int)
let countReducer = (prev, action) => {
switch action {
| Inc(num) => prev + num
| Dec(num) => prev - num
}
}
let atom = Utils.AtomWithReducer.make(0, countReducer)
let (value, dispatch) = Atom.use(atom)
Inc(1)->dispatch
A hook that returns only the update function of an atom. Can be used to access writeOnly atoms.
let atom = Jotai.Atom.make(1)
let setValue = Jotai.Utils.useUpdateAtom(atom)
setValue(prev => prev + 1)
A hook that returns only the value of an atom. Can be used to access readOnly atoms.
let atom = Jotai.Atom.make(1)
let value = Jotai.Utils.useAtomValue(atom)
Returns a function that can be used to reset a resettable atom.
let atom = Jotai.Utils.AtomWithReset(1) // value: 1
let (_, setValue) = Jotai.Atom.use(atom)
setValue(2) // value: 2
let resetValue = Jotai.Utils.useResetAtom(atom)
resetValue() // value back to: 1
Allows to use a reducer function with a primitive atom.
type actionType = Inc(int) | Dec(int)
let countReducer = (prev, action) => {
switch action {
| Inc(num) => prev + num
| Dec(num) => prev - num
}
}
let atom = Jotai.Atom.make(0)
let (value, dispatch) = Jotai.Utils.useReducerAtom(atom, countReducer)
Inc(1)->dispatch
This package was greatly inspired by re-jotai. I just preferred to have a different syntax for the get/set functions.
These functions are not (yet) supported.
- atomWithObservable
- atomWithHash
- atomFamily
- selectAtom
- useAtomCallback
- freezeAtom
- splitAtom
- waitForAll
- useHydrateAtoms