RecoilJS in practical - complex application
How I used RecoilJS in Refi App
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 🤘
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
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
- 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
useRecoilStateand 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
useStatewhich 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.
atomstate can easily convert to
selectorand 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
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
selectorvalue 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
atomvalue 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
- ⚡️ Recoil is fast and easy to use
- 🆙 It will boost productivity by "Use
useStateand convert it to
- 😤 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.