The main API to bind atoms and actions to a component lifetime is reatomComponent. It wraps your regular react component and put ctx into the props. There is no additional rules or behavior, you can use any other hooks, accept props, return any valid ReactNode. But if you using ctx.spy, just like in any computed atom, it will subscribe to the passed atom and rerender from by changes.
You can describe props types in the generic, it can be any kind of values, regular string, JSON, and atoms too. For example, here is a controlled component with atom state.
One of the most powerful features of reatomComponent is that you are not bound by react hooks rules, you could use ctx.spy in any order, right in your template.
Do not forget to put the component name to the second argument, it will increase your feature debug experience a lot!
useAtom is your main hook, when you need to describe reusable logic in hight order hook. It accepts an atom to read it value and subscribes to the changes, or a primitive value to create a new mutable atom and subscribe to it. It alike useState, but with many additional features. It returns a tuple of [state, setState, theAtom, ctx]. theAtom is a reference to the passed or created atom.
Another use case for the hook is describing additional computations inside a component (create temporal computed atom). It is possible to put a reducer function to useState, which will create a new computed atom (setState will be undefined in this case).
The reducer function is just the same as in atom function. You could spy a few other atoms. It will be called only when the dependencies change, so you could use conditions and Reatom will optimize your dependencies and subscribes only to the necessary atoms.
What, why? In the example bellow we creating “inline” atoms, which will live only during the component lifetime. Here are the benefits of this pattern instead of using regular hooks:
You could depend your atoms by a props (deps changing will cause the callback rerun, the atom will the same).
Easy access to services, in case you use reatom as a DI.
Component inline atoms could be used for other computations, which could prevent rerenders (see above).
Created actions and atoms will be visible in logger / debugger with async cause tracking, which is much better for debugging than useEffect.
Unify codestyle for any state (local and global) description.
As react docs says↗, sometimes you need a callback, which depends on often changed value, but you don’t want to change a reference of this handler, to not broke memoization of children components which depends on the current. In this case, you could use atom and read it value lazily.
Here is a standard react code, handleSubmit reference is recreating on each input change and rerender.
Here handleSubmit reference is stable and doesn’t depend on input, but have access to it last value.
useAtom accepts third argument shouldSubscribe which is true by default. But sometimes you have a set of computations not all of which you need in the render. In this case you could use atoms from useAtom without subscribing to it values.
Here is how could you share data created and managed in parent, but used in children.
Here is another example of in-render computations which could be archived without rerender.
useUpdate is a similar to useEffect hook, but it allows you to subscribe to atoms and receive it values in the callback. Important semantic difference is that subscription to atoms works as onChange hook and your callback will call during transaction, so you need to schedule an effects, but could mutate an atoms without batching. Subscriptions to a values works like regular useEffect hook.
The most common use case for this hook is to synchronize some state from a props or context to an atom.
And it works well in the opposite direction, you could synchronise an atom’s data with the local state, or do any other kind of effect. You can use useUpdate as a safety replacement for onChange + useEffect.
For example, you need a controlled input from the passed atom.
Here is a naive implementation:
Here is a simpler and more reliable implementation:
If you have an atom with a promise and want to use its value directly, you could use useAtomPromise. This function relies on React Suspense↗ and throws the promise until it resolves. It can be useful with reatomResource.