DEV Community

loading...

Why I stopped using Redux and Used Recoil Instead

akashshyam profile image Akash Shyam Updated on ・4 min read

What's wrong with Redux?

Redux is not perfect, but it is by far the most popular state management library used with React. Let's look at what's not so great in redux:

  • Giant Learning Curve
    There are so many concepts to learn like actions, action creator, reducers... and when we throw class based and functional components in the mix along with a different way of dispatching while using thunk etc, It can really scare a beginner

  • Huge Amount of Boilerplate
    Everytime we want to setup a redux app, we have to create reducers, combine them, create a store, add middleware, link to devtools, computed values etc. We need to add so many 3rd party libraries which have a config of their own and introduce another layer of complexity.

  • Restructuring Folder Structure
    The react component based approach does not align itself very well with the redux way of splitting business logic. If we want to introduce redux into an existing react app, then we need to change the file structure and a lot of code has to be changed.

Context API

The context API is not really a solution for this. It solves the prop drilling problem... not global application state. You cannot pass data across siblings using context. The child will have to update the parent which will update another child(the sibling).

Why Recoil?

** An a **

Terminology with Recoil

Unlike redux where we have so many concepts to understand... there are only a few in Recoil

Atom

This is the easiest part of the terminology.... an atom is basically a piece of state

Selector

A piece of state that is calculated on the basis of another atom(s) or selector(s)

Recoil

Let's begin by installing recoil

npm i recoil
Enter fullscreen mode Exit fullscreen mode

Whenever we want to use recoil, we need to have the RecoilRoot component somewhere in our component tree.

import React from 'react';
import {RecoilRoot} from 'root';

export default function App() {
  return (
    <RecoilRoot>
      <h1>Recoil Demo</h1>
    </RecoilRoot>
  )
}
Enter fullscreen mode Exit fullscreen mode

When we want to create an atom, we use the atom function.

import React from 'react';
import { RecoilRoot, atom } from 'recoil';

const counter = atom({
  key: "counter",
  default: "0"
});

export default function App() {
  return (
    <RecoilRoot>
      <h1>Recoil Demo</h1>
    </RecoilRoot>
  )
}
Enter fullscreen mode Exit fullscreen mode

Each atom() takes in 2 fields:

  1. Key
    The key is the name our atom. It must be unique in our application and we use it to get the value of the atom.

  2. Default
    The default is the initial value of our atom

We've created an atom but we'll also need to access it. We use the useRecoilState hook

import React from 'react';
import {RecoilRoot, useRecoilState, atom} from 'root';

const counter = atom({
  key: "counter",
  default: "0"
});

export default function App() {
  const [number, setNumber] = useRecoilState(counter);

  return (
    <RecoilRoot>
      <h1>Recoil Demo</h1>
      <button onClick={() => setNumber(number + 1)}>{number}</button>
    </RecoilRoot>
  )
}
Enter fullscreen mode Exit fullscreen mode

We pass in the counter atom to the useRecoilState. Very similar to the useState hook in react, useRecoilState also returns the value of the state and a function to set the state.

I've added a simple button that shows the value of number. When we click on it, we increment the number state using the setNumber() function.

This atom can be used in another component too. In case we only want to access the value of the number atom, we can use the useRecoilHook.

function Display() {
  const number = useRecoilValue(counter);
  return <p>{number}</p>
}
Enter fullscreen mode Exit fullscreen mode

Derived State

Let's begin by understanding what derived state actually is. It's a piece of state that is calculated on the basis of another state.

It's very easy to do this in recoil. We can use the selector() function. A selector is a pure function that takes in atoms or other selectors. We'll cube the value of our counter.

const cubed = selector({
  key: "cube",
  get: ({ get }) => get(counter) ** 3
})
Enter fullscreen mode Exit fullscreen mode

The key field is nothing new... it specifies the name of our state, as I mentioned earlier, It must always be unique. The get field is where things get interesting. I agree it the syntax is complicated but this gives us a lot of power and expands the possibilities. Whenever an atom which the selector uses changes, the selector is recalculated Let's go through the code line by line.

We are giving a function to the get field. Recoil passes an object into that, from this object we are destructuring the get field. The get field is a function that allows use to pass in the key of an atom or selector and access it's value. Then we are raising it to the power of 3. Here we have used only one atom but we can use multiple atoms for computations.

import {selector} from 'recoil';

const cubed = selector({
  key: "totalPrice",
  get: ({ get }) => {
    get(numState) ** 3
  }
})
Enter fullscreen mode Exit fullscreen mode

Folder Structure

Let's say the we have 2 broad categories of state in our app: users and todos. All the atoms go in /atoms and the selectors go in /selectors. The atoms related to users will go in /atoms/users.js, the atoms related to todos will go in /atoms/todos.js and so on.

That's all for now, thank you for reading until here. I hope you guys liked this post, if you did please like the post and follow me. Bye 👋

Discussion (24)

pic
Editor guide
Collapse
mzzfederico profile image
Federico Muzzo • Edited

I think this article comes from the wrong mindset about approaching Redux as a methodology for state management, sorta the same mindset that most people have when starting to learn it and immediately want to ship stuff to the moon. Even this library seems to be doing quite a bit more than the simplest iteration of Redux.

As it has been said elsewhere in the comments, the boilerplate and folder architecture in big projects is scarcely an issue; Redux has also got a fancy toolkit with hooks that make it pretty much plug and play. Middlewares, if you know asynchronous programming, are useless to be honest.

Moreover, the "simplest" Redux approach is just made of reducers and actions. Dispatch an action, get a new state.

Store is just a redundant word for state; selectors are just sugar syntax to pick stuff from the state; action creators are functions that return actions. Just skip all of these and use useReducer, and you pretty much need zero boilerplate, zero scratching the head, honest to God replicable, testable and compact open ended state machines. If you want more, just add React Contexts, which are "native" to React just like Hooks.

Combine the two and you don't need any library for state management until you actually outgrow small local states or shared contexts with simple actions, or actions that influence multiple states at the same time or so on. By the time you outgrow those, reducers and actions can be used just as good with Redux itself by injecting them into the components with the provided utilities, or imported to the canonical "store".

If you reduce Redux to reducers and actions, you'll see that the semantic complexity and curve of learning never really takes off, compared to the bunch of words for Recoil in this article.

Collapse
akashshyam profile image
Akash Shyam Author

If you look at the title, i'm not asking people to switch to recoil and throw redux in the bin. I'm just saying my viewpoint. If a beginner is learning react and has just learned the concept of "hooks".... recoil is much easier to grasp. Then maybe he can move onto redux. I took almost 2-3 months to properly grasp redux. On the flip side, i learned recoil in a day or two. Redux has so many ways to dispatch/connect to state and when we use something like redux thunk we have a different way of dispatching. I'm not saying not to use redux, I'm just advocating recoil as an option. Of course recoil has it's disadvantages.

Collapse
mzzfederico profile image
Federico Muzzo • Edited

The core point is that a beginner shouldn't even need Redux (the library) or any state management library unless they have a specific issue that Context or the new hooks can't deal with.

useReducer comes with React. 🙂 Can't get more official than that.

You don't even need to look up to Redux complexity when that complexity is a. being solved by the new toolkit everyone is encouraged to use b. not pertaining to a beginner.

In fact, global state should be avoided at all costs in my opinion as it leads to bad patterns and relying on too many actors.

Let's stick to what React does. 🙂

Thread Thread
akashshyam profile image
Akash Shyam Author

I agree with you. Only stuff like auth should be stored globally. We should try and keep as much as we can in component level state except when we have to share props downwards in the component tree by many levels.

Thread Thread
mzzfederico profile image
Federico Muzzo

Yes, I'm afraid too many people never got the memo about React Context. 🙂

Collapse
diogo405 profile image
Diogo Goncalves

I don't know why people still use Redux. Recoil is much simpler and easier!

Collapse
johnfrades profile image
John Frades

Redux is already an established library and well maintained. If you're working on a commercial product, adding a library because its simpler and easier isn't always the case. Especially that Recoil is still in Experimental stage. Companies jwouldn't risk their product using an experimental stage library

Collapse
nicozerpa profile image
Nico Zerpa (he/him)

Redux has been so popular for a long time. That means there are lots of libraries that work well with it. As Recoil is still a young project, you don't have so many libraries available, at least for now.

Also, there are tons of information online about Redux. That's very useful if you find a bug or a problem using the library because it will be easier to find how others solved that problem.

If you use Recoil and something goes wrong, it will be way harder to google how to solve it. That's also because it's a new tool.

Redux is better suited for large, complex applications. In these large codebases, the boilerplate code isn't that much of a problem.

Collapse
jyooi profile image
jyooi

I don't know why those people thinking of other ppl using that library are not a good idea. They don't understand there always have the legacy codebase and it is still working fine. People don't risk their production code with those experimental libraryy.

Collapse
stojakovic99 profile image
Nikola Stojaković • Edited

Most probably because of the ecosystem. That's one of the primary reasons why most of the websites still use PHP. Also, Recoil is an experimental library.

Collapse
foyzulkarim profile image
Foyzul Karim

Still there are thousands of React apps which are using class components, for various reasons. How can we use recoil in these projects?
What I do is, I mix and match the redux and react state in my app and it works just fine.

Collapse
chasm profile image
Charles F. Munat

So atom and selector are in global state somehow? I don't see where they are imported. And how does RecoilRoot know about them?

This doesn't make much sense to me. What am I missing?

Collapse
akashshyam profile image
Akash Shyam Author

Atom and selector are not in global state.... they have to be imported.

Collapse
chasm profile image
Charles F. Munat

So maybe show the imports in your examples? Examples should be complete and not assume any prior knowledge of the code you're explaining.

Thread Thread
akashshyam profile image
Akash Shyam Author

Actually the code snippet was getting very big and I did not want to bore the reader by showing the imports. Will add imports from now on, thanks!

Collapse
drarig29 profile image
Corentin Girard • Edited

You are not importing useRecoilState() in the first snippet you mention it.

Collapse
akashshyam profile image
Akash Shyam Author

Thanks for the tip.... sorry about that input

Collapse
oliverradini profile image
OliverRadini

Is it possible to use recoil with frameworks/libraries other than react? One thing I like about Redux is that it disconnects state management from the rest of the frontend stack.

Collapse
akashshyam profile image
Akash Shyam Author

A state management library for React
Recoil official Website

Recoil was designed specifically for react to make it easy to use and adhere to the react idealogy

Collapse
oliverradini profile image
OliverRadini

One of the main advantages I've seen with React is that it doesn't try and enforce an ideology across the stack, but allows you to choose your own tools. I think that a distinct advantage of redux is that state management is framework agnostic.

Collapse
nicozerpa profile image
Nico Zerpa (he/him)

So, Recoil is inspired by React Hooks... interesting!
Thank you for sharing, Akash 💯

Collapse
akashshyam profile image
Akash Shyam Author

Glad you liked it!

Collapse
lyrod profile image
Lyrod

Import from 'root' ?

Collapse
akashshyam profile image
Akash Shyam Author

Thanks for letting me know.... it was a typo