
Recoil – A state management library for React - dar8919
https://recoiljs.org/
======
mariusandra
I'm someone who through sheer coincidence (the right projects at the right
time) happened/lucked into developing a React state management solution
([https://kea.js.org](https://kea.js.org)). I've probably sunk hundreds of
hours into this project by now.

5 hours before this HN post I asked for comparisons with different site
management libraries on Github here:
[https://github.com/keajs/kea/issues/106](https://github.com/keajs/kea/issues/106)

React state management is indeed a mess, meaning there are so many options to
choose from. Unfortunately, even for me, a library author, it's hard to
evaluate all of them properly. It would take just too much time and you never
know where the real problems in any framework lay before you get neck-deep in
code. And then you're too far to switch to another framework anyway.

Someone should really map out this landscape in more depth than just an
awesome list. I hope the issue linked above can spark some discussion.

In any case, I personally think Kea is a very good solution for React state
management, yet obviously I'm biased. Shrug.

And, to keep it on the topic, Recoil seems very low level and I think you need
to invent a lot of things yourself to get a full app out of it. Cool to see
people trying stuff though :).

And it's from Facebook so who knows, just by proxy it might become the default
"atom" and someone will build molecules out of them...

~~~
volkandkaya
Keajs has been amazing I upgraded from 0.28 to 2.0 yesterday and had 1 small
issue, had to delete [actions.] from the reducers.

I use to use just Redux and it was such a pain.

I know you have added even more features in v2 that I will need to take
advantage of.

If you need to add examples [https://versoly.com/](https://versoly.com/) is
what I built on top of keajs.

Has about 8 logic stores that have 100s of actions, thunks, reducers and some
interesting selectors.

~~~
mariusandra
Hey! Thanks for the comment and that's really cool! Your product looks really
slick as well!

Would you mind posting in this "who's using kea" issue about versoly as well?

[https://github.com/keajs/kea/issues/35](https://github.com/keajs/kea/issues/35)

------
weeksie
I'm not seeing how this works with more complex state flows. Doesn't seem much
better than useReducer.

Frankly, for state management I still haven't found anything that beats Redux
on its own without thunks or sagas or any of that bullshit. This is despite
doing my level best to see if useReducer on its own would be sufficient. It's
not.

Thunks are unmaintainable. Sagas are put together with bailing twine and rely
too much on generators for my taste. (The source code is smart but it's also
wildly complex.) All of it is castles in the sky for no good reason. You don't
need any of that anyway.

~~~
vosper
> I still haven't found anything that beats Redux on its own without thunks or
> sagas

There was a period in the early days of Redux where MobX [0] (and, perhaps to
a lesser extend, MobX State Tree [1]) was the main competitor to Redux that I
used to hear about. They both seem to be actively developed, but I don't hear
so much about them any more. Have you ever look at either of them?

BTW I am 100% with you on Sagas.

[0] MobX
[https://mobx.js.org/README.html#introduction](https://mobx.js.org/README.html#introduction)
[1] MobX State Tree: [https://mobx-state-
tree.js.org/intro/philosophy](https://mobx-state-tree.js.org/intro/philosophy)

~~~
armandososa
MobX State Tree advocate here. We have a VERY complex state that needs to be
synced with the server and persisted locally and nothing fulfilled our needs
like MST.

Also, sign me up to the Sagas-are-bullshit club.

~~~
topspin
Mobx itself is insufficient? What does mobx-state-tree provide that mobx does
not? The README doesn't convey anything meaningful.

~~~
armandososa
Well, you know how MobX itself is very unopinionated? MST is very structured
and opinionated. It's also immutable which means you get snapshots of every
mutation to the tree which is very useful in almost all cases.

------
saranshk
Here's an awesome video from the library author explaining a bit more about
Recoil from today's React Europe live stream if anyone is interested:
[https://www.youtube.com/watch?v=_ISAA_Jt9kI](https://www.youtube.com/watch?v=_ISAA_Jt9kI).

------
knubie
Sounds a lot like re-frame[1] (which I believe predates Redux), they even call
the state "atoms."

[1] [https://github.com/Day8/re-frame](https://github.com/Day8/re-frame)

~~~
davidmccabe
The term 'atom' is a clojure-ism, that's where both I and reframe get it from.

~~~
rjknight
Re-frame's atoms are actually Reagent's 'ratoms' ('reactive atoms'). They're
built on Clojure atoms, but can reactively prompt a re-render of any component
that depends on them when the content of the ratom changes.

Re-frame wraps Reagent, and introduces the concept of "subscriptions". A
subscription either returns the content of an atom, or state derived from it,
equivalent to Recoil's selectors. Re-frame also introduces the concept of a
global application DB, a single atom that contains various pieces of state,
such that you can develop your entire app around it.

I haven't tried Recoil, but I'll give it a shot on my next JS project - I tend
to use ClojureScript for front-end precisely because I find the
Reagent/Reframe approach simpler and more effective than any of the plain JS
React approaches (for complex apps, anyway).

------
jwiley
It would be useful to have a more direct comparison between this and Redux
(assuming its not on the website and I missed it). In what use-cases is it
preferable, in which would it not be a good fit? In the comments you mention
O(1) vs O(n), diving more deeply into that would be helpful as well.

~~~
portlander12345
I’m working on a detailed comparison for the docs. Thanks for the feedback!

------
cwackerfuss
Check out easy-peasy. Ive used plain ol redux, mobx, and xstate, but easy-
peasy is the fricken best. It's basically a redux wrapper that combines redux,
thunks, reselect, redux logger, immer, and more into a super intuitive
interface. The typescript support is super good and interacting with the API
feels very modern and hook-driven.

[https://github.com/ctrlplusb/easy-peasy](https://github.com/ctrlplusb/easy-
peasy)

~~~
nwienert
If you want even cooler try overmind:

[https://overmindjs.org](https://overmindjs.org)

But Recoil is slightly different, designed to be “component first”
essentially. Not global. It’s how my own personal mobx based library works.
But this one likely has concurrent mode baked in.

------
josemaenzo
I'm happy that we are moving away from the redux-like standard. I've tried the
API in a dumb example and it looks clean and easy.
[https://codesandbox.io/s/three-buttons-example-with-
recoil-q...](https://codesandbox.io/s/three-buttons-example-with-recoil-qiqhf)

Still don't like the extra naming that you have to think of for every
atom/value. Or also the key: prop that you have to define for every atom. It
seems redundant for me.

And also, as a bundle-phobia guy I am. I think 22kb as extra library is ok but
it could be better.

Liking a lot Recoil as solution for the three-button problem. I still think
that the patch pattern I use with dop is better. In terms of simplicity and
extra KB. This is the same example [https://codesandbox.io/s/react-dop-
nhj0j?file=/store.js](https://codesandbox.io/s/react-dop-nhj0j?file=/store.js)

But I guess I say that because I'm the creator of dop. So I'm so open to
critics :)

------
flowerlad
What is it about React that state management is such a such a hassle? This is
not the case in other frameworks.

Consider iOS for example. Just add fields in App and you're done:
[https://developer.apple.com/documentation/swift/maintaining_...](https://developer.apple.com/documentation/swift/maintaining_state_in_your_apps)

Similarly in ASP.NET: [https://docs.microsoft.com/en-us/previous-
versions/aspnet/75...](https://docs.microsoft.com/en-us/previous-
versions/aspnet/75x4ha6s\(v%3Dvs.100\))

Same in JSP: [https://javabeginnerstutorial.com/jsp-tutorial/state-
managem...](https://javabeginnerstutorial.com/jsp-tutorial/state-management-
in-jsp/)

But in React it is such a huge issue, and there are multiple competing
solutions. There must be something wrong with the design of React that is
causing this.

~~~
concerned_user
React is not a complete framework more of a templating engine and nothing
more, it allows you to use any state management you want. It also makes it
easy to add to existing projects without requiring rewrite of everything from
the ground up.

~~~
LargeWu
The downside of this is that it's often the complete wild west when building
and doing maintenance. It's not uncommon to end up with wildly different state
management solutions in every project because the prevailing winds change so
frequently. This can have a big effect on productivity and morale. It's one of
the main reasons I'm trying to get out of programming for my profession. I'm
so fucking tired of having to chase the flavor of the month.

------
bfrydl
Seems like compared to Redux this would make server-side rendering very
challenging. Each atom is a global singleton so I'm not sure how you could
render individual requests.

~~~
davidmccabe
It’s actually designed to make server rendering easy. We’ll add a guide about
this eventually. Atoms aren't global singletons: their values are scoped to
React trees.

~~~
mleonard
Can you talk about SSR here just a little to give us an idea of how recoil
makes it easy?

~~~
davidmccabe
Well, I should say "doesn't make it harder". The `RecoilRoot` component
accepts a prop called `initializeState` that lets you specify the state of all
atoms in the initial render.

~~~
evv
Shouldn't the app be allowed to "pull" the required state from the db, rather
than having to "push" the initial state into the root of the app? It's not
like we should dump the whole database into atoms just in case the app needs
to look up one item, right?

I'm mostly curious how this might tie into a server-side DB. Recoil's API
provides the fundamentals for a firebase-like persistence system that allows
people to skip the complexity of GraphQL, and just use the type system
provided by the language (flow/ts/reason).

In any case, congrats on launching such an elegant API. This is one of the
nicest reactive systems I've seen for React :-D

~~~
davidmccabe
We are planning in the next few weeks an overhauled persistence API. Among
other things this will add the ability to provide a callback in
`initializeState` rather than a value. However, this doesn't help if you need
to do async work to retrieve the value. The way we generally think of SSR is
that you get a single render pass and then you're done, no time for async
work. So for hitting a database you want something like Relay that statically
knows your data dependencies and can do a single request to initialize. It's
true that there's some complexity there, but there are also great solutions to
really hard problems. Recoil doesn't attempt to address that space.

------
mmerickel
Is there any support for changing multiple atoms at once / batch? This is
where reducers shine to me - dispatching a single action from the ui in redux
that multiple reducers can listen to and use to update their state.

Also is there any support for getting the values of atoms outside of a hook?
For example from an async action that is not coupled to the render loop which
also wants to know the current value.

~~~
davidmccabe
If you update multiple atoms within a React batch, they will be updated at the
same time, just as with React local state. You don't need to wrap the changes
in anything to have them occur together.

In other words, this updates both of the atoms together:

    
    
      const [a, setA] = useRecoilState(atomA);
      const [b, setB] = useRecoilState(atomB);
      ...
      onClick={() => {
        setA(a => a + 1);
        setB(b => b + 1);
      }}
    
    

If the new values of multiple atoms are interdependent on each others' current
values, it's possible to update multiple atoms together using the
transactional/updater/function form, but we need to add a nicer interface for
doing this. Coming soon! The nicer interface would probably look something
like this:

    
    
      const update = useTransactionalUpdate([atomA, atomB]);
      ...
      onClick={() => {
        update(([a, b]) => [a + b, b - a]);
      }}
    

It's then easy to make a hook that provides a reducer-style interface over a
set of atoms. But now, unlike with Redux or useReducer, each atom still has
its own individual subscriptions!

~~~
mmerickel
It seems like something could be written around useRecoilCallback() to
watch/get the current value of an atom outside of a React component. Does that
sound right?

~~~
davidmccabe
For a specific set of atoms you could subscribe to them with a component and
then use an effect to send the values out. For all atoms you could use
useTransactionObservation.

------
sheerun
In a year people will rediscover MobX I guess...

~~~
lai
Lol, MobX literally uses the concept of atoms under the hood.

------
bodhibyte
Can anyone shed some light on if and how this might be used together with
xstate ([https://xstate.js.org/](https://xstate.js.org/)) which is based on
the SCXML spec?

~~~
davidkpiano
I'll experiment with this.

------
sawyerjhood
Great work on this davidmccabe! I remember hearing about this just before I
left FB and am so glad that it is open source now.

------
rhacker
Seems to be roughly the same amount of boilerplate as useContext, so I don't
fully understand the separate purpose for it?

~~~
baddox
Recoil allows you to create atoms and selectors in loops without having to add
an entire new Context.Provider component to the root of the React component
tree, which would obviously not be viable since the entire tree would need to
be torn down each time.

~~~
beirut_bootleg
This is the part that completely lost me. Why do you need an additional
context for each item? Isn't one context holding all items enough?

~~~
baddox
If you have a lot of pieces of data in one React context, _every_ component
that uses any little piece of that data will re-render whenever _any_ part of
the data changes.

~~~
rhacker
React has more intelligence built in than that. That's definitely not quite
how it works.

~~~
davidmccabe
React doesn't have to commit to the DOM if there are no changes, but it still
has to render each component and compare the output. Even if the component is
memoized, it still has to compare the props. This is fast enough most of the
time but it can become a bottleneck in some cases.

~~~
baddox
Yes, and component memoization (and PureComponent and shouldComponentUpdate)
only prevents re-rendering of the component's descendants. But _every_
component that uses a context value will still re-render every time that
context value changes, which could potentially be way too many.

For example, if every Cell component in a big Table component is using the
same context value, they will all need to re-render when _any_ cell value
changes, regardless of whether the Cell component or some of its descendants
are memoized. This is a common pattern in Redux, which solves this problem and
will only re-render the Cells which are using cell values which have changed.
Recoil would provide the same benefit.

------
rsify
I wish he would have shown the heavy tree example in 11:55 without the
library, seems cute and all but if you don't provide a comparison it's hard to
take seriously.

------
ecnrvsrp
Anyone else see Svelte stores when they look at this?

------
saranshk
Conceptually, this looks very similar to observables and RxJs. Should be
interesting to explore further.

------
pppm
Ffff

