Hi there, I just use Recoil for my own product for the first time.
So I decided to share my own experience when using Recoil ๐ค
Why?
With the non-requirement of Refi App, it must be fast to bring the best DX so I need something to manage the state in a very optimized way
Why not Redux? Zustan? DVA?
- The boilderplace is so fukin hard. Besides, it really hard for optimizing to only render a component that subscribes to a sub-tree state. I need to use
selector
,memorize
,immutable
, ...
Why not MobX? MST?
- It has been a long time since I last use Mobx, MST. It's cool, but now the world has changed a lot, no more Class component, so I don't know it supports a lot.
- One more thing I don't want to use MobX is that the API is changed a lot in each major version. No! I don't want to use an outdated library for the rest of my life
- I feel can not control how Component will render when I use MobX
Why Recoil?
- It solves my concern, each component is subscribed to a very small state object (called atom) and only render once they changed
- It plays nice with Functional Component. You can easily change
useState
touseRecoilState
and vice versa. It's cool because "Alway use local state, only move it to global once needed" - I can map the product concept to state in my brain. A cell in a table should be an atom, so that the cell will render on its own.
How can I struct my state?
When using recoil, your state will build from pieces of atoms - A bottom-up approach. So that if you don't have a strategy for structuring it, you will end up with tons of atom
I decided to orders those atoms by
- firebase atoms
- navigator atoms
- UI atoms
- hotkeys atom
If it is biz state, I divided it by domain If it is for something to manage display, I divided it by its function
As you can see in the images, I also make a .action.ts
files. Once using recoil in a complex app, you will often need to update the state of many atoms for one action.
For eg: Once users click on the Commit
button, I will need to submit all the modified/new/deleted documents to the server, I also need to update a UI atom to show loading.
By splitting all actions into .action.ts
file. I can list out all the use cases and conveniently not mess my mind once add or edit something.
One more thing is all the atoms, selectors must postfix with Atom
. If not your brain will get confused when using it. Is this object is Atom Value, Atom State, or just a local state?
For that strategy, RefiApp tech about 60 atoms object so far. I'm happy with the current status but I think I gonna divide it for smaller if the app is grow
The funny parts
- As I write above, it really easy to convert from
useRecoilState
touseState
which is free my brain a lot. I don't need to ask myself, should I put it at global every time I try to introduce a new state. - An
atom
state can easily convert toselector
and vice versa. Why I will need that?
In the image above, I have a propertyListAtom
to store the propertys
that will show in each collection table. It will have an empty array []
as the default value. But I have a case that if users access a collection for the first time, I will generate some property
to put on that list so that I introduce a null
type for that atom. If I change the type of propertyListAtom
then I gonna need to find everywhere using that atom to make an update.
No, you don't need to do that!. I just add a new atom propertyListCoreAtom
and turn my old atom one to selector
. Really enjoy!
- Components will only render if its subscribed atoms update which is my own goal. No more energy to put on a stupid thing like
redux
andselector
...
The awful parts
- You have to write all the logic in a component, there is no official way to mutate a state from outside. I know they have reason to make it, but it feels poor for developers to follow it. But I found a way to eliminate that github.com/facebookexperimental/Recoil/issu..
- There are some issues on performance still not solve yet. The components will render if the
selector
value is not changed (their dependencies changed) github.com/facebookexperimental/Recoil/issu.. - I have a collection contains for about 100 documents. And I tried to update 100 atoms once I received the document data, the app is hanged. The recoil and react is not smart enough to batch those update! But it turns on an idea in my head ๐ก which this approach I can batch update my app which out to do lots thing and the result is incredible. I called this approach is Separated tree timeline, and it also applicable for Redux, let's do it on the next post
- You can not subscribe to an
atom
value without making your component rerender. I solve that by introducing RxJS to my code, not that hard when combining them - The only debug tool that worked for me is
console
. Despise there some DevTool for Recoil but it's buggy and the DX is bad
Takeaways
- โก๏ธ Recoil is fast and easy to use
- ๐ It will boost productivity by "Use
useState
and convert it touseRecoilState
when needed" - ๐ค You gonna need a strategy to struct your atoms because it will be lots more
- โ ๏ธ It still lacks some support on the advantage cases, you will need help for other libs.