RecoilJS in practical - complex application
Thanh Minh
Posted on April 1, 2021
Hi there,
I just use Recoil for my own product for the first time.
Refi App - A tool to make developer less painful when interacting with Firestore DB
Thanh Minh ・ Mar 30 '21
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 which subscribe 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
- 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 atom - 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 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 to .action.ts
file. I can list out all the use cases and convenient to 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
There is a way to update states on recoilJS outside of component? #289
orhalimi posted onSo I'm trying recoilJS for a js game that I am building and it pretty neat, but the need to update atoms from components only feels like a limitation.
To create a game loop, I put all the logic on empty component so I will be able to read and write states. Even if I will construct the logic outside of the component, I will need especially move different stats around all the time. There is a way to update atoms outside of react component (not via hooks)?
- There are some issues on performance still not solve yet. The components will render if the
selector
value is not changed (their dependencies changed)The component rerender even the value from selector is not change #924
thanhlmm posted onhttps://codesandbox.io/s/recoil-test-8jove?file=/src/App.js
- I have an atom to keep track an array of item -
AtomA
- A selector to validate the length of above array -
SelectorB
So every time I add new item to
AtomA
but theSelectorB
still return same result, the component subscribe to it always rerender</div> <div class="gh-btn-container"><a class="gh-btn" href="https://github.com/facebookexperimental/Recoil/issues/924">View on GitHub</a></div>
- 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.
- I have an atom to keep track an array of item -
Posted on April 1, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.