RecoilJS in practical - complex application

RecoilJS in practical - complex application

How I used RecoilJS in Refi App

ยท

5 min read

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? Alt Text

  • 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 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

Lots of atoms

I decided to orders those atoms by

  • firebase atoms
  • navigator atoms
  • UI atoms
  • hotkeys atom

My atoms

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.

Alt Text

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

  • 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

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

  • 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 Seprated tree timeline
  • 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.
ย