RecoilJS in practical - complex application
Tags: javascript, react, recoiljs
Published: 2021-04-01 16:07:19

Hi there,
I just use Recoil for my own product for the first time.

{% link https://dev.to/thanhlm/refi-app-a-tool-to-make-developer-less-painful-when-interacting-with-firestore-db-23of %}

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

**Why Recoil?**
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cpzj5eam5j7w5xhjmyfm.gif)
- 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` to `useRecoilState` 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

![Lots of atom](https://media.giphy.com/media/3oxHQfQJqCpqtoeDZK/source.gif)

I decided to orders those atoms by
- firebase atoms
- navigator atoms
- UI atoms
- hotkeys atom

![My atoms](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7p0ylj96q71psoi8jf9f.png)

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.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j16ajajmxh1k45lfzzoz.png)

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
![Funny parts](https://media.giphy.com/media/ZqlvCTNHpqrio/source.gif)
- As I write above, it really easy to convert from `useRecoilState` to `useState` 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 to `selector` and vice versa. Why I will need that?
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gzbv3xorj1awkkm0az2t.png)

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` and `selector`...

# The awful parts
![awful parts](https://media.giphy.com/media/h5Y8UipmlqHCw/source.gif)
- 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 https://github.com/facebookexperimental/Recoil/issues/289 %}
- 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 https://github.com/facebookexperimental/Recoil/issues/924 %}
- 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
![Seprated tree timeline](https://media.giphy.com/media/3ornjIhZGFWpbcGMAU/source.gif)
- 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 to `useRecoilState` 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.