Used for optimum state management because Context-API is a McQueen in Cars 3 and renders static things that aren’t supposed to be rendered.

The main concept behind Recoil is to have a global state variable called as an atom that can be read and written by various functions.

In short, atom represents a reactive state, its like the count variable in useState(0).

Its a good practice to make an atom in a different file and then import it in the App.jsx

Here is what the syntax of making an atom looks like:

store\\atom\\count.jsx :

import { atom } from 'recoil';

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

Now, to interact with Recoil, there are mainly three hooks:

  1. useRecoilState : Similar to use-State, and its task is to read the current value of the atom and provide a setter function that can update the value of the atom.
  2. useRecoilValue : The task of this hook is to only read the current value of the atom, you cannot update the value.
  3. useSetRecoilValue : This hook can only update the value of the atom, you cannot read the value of the atom, its like set-Count function.

To give you a gist of it, this is what it can mainly do

Hook Can Read? Can Write? When to Use
useRecoilState ✅ Yes ✅ Yes When you want to both read and update state
useRecoilValue ✅ Yes ❌ No When you only need to read the state
useSetRecoilState ❌ No ✅ Yes When you only need to update the state

Example code - Here, if you see closely with the react chrome extension, no re-rendering is happening through the buttons, to make sure that doesn’t happen, I have added a log in the function Buttons() .

import { countAtom } from "./store/atoms/count";
import './App.css';
import { RecoilRoot, useSetRecoilState, useRecoilValue } from 'recoil';

function App() {
  return (
    <div>
      <RecoilRoot> // everytime recoil is used, at that time the component using recoil should go under this wrapper.
        <Count/>
      </RecoilRoot>
        

    </div>
  )
}

function Buttons() {
	const [count, setCount] = useState('');
  const adder = useSetRecoilState(count);
  const subtractor = useSetRecoilState(count); // setter
  console.log("Re-rendered by buttons") // The log that I have added everytime button is pressed but yet rendering doesnt happen.
  return <div>
    <button onClick={() => {
      adder(count => count + 1)
    }}>Increase</button>
    <button onClick={() => {subtractor(count => count - 1)}>Decrease</button>
  </div>
}

function CountRerenderer() {
  const count = useRecoilValue(countAtom);
  return <div>
      {count}
    </div>
}

function Count() {
  return (
  <div>
    <CountRerenderer/>
    <Buttons/>
  </div>
  )
}

export default App;

Selector in Recoil

A selector lets you read, transform or combine Recoil atoms into a new combined value, it is kind of like useMemo, let me tell you why in the following example

import { atom } from "recoil";

export const networkAtom = atom({
    key:"networkAtom",
    default: 104
});

export const jobsAtom = atom({
    key:"jobsAtom",
    default: 4
});

export const notificationsAtom = atom({
    key:"notifAtom",
    default: 12
});

export const messagingAtom = atom({
    key: "messageAtom",
    default: 0
});

export const totalNotificationSelector = selector({
    key: "totalNotificationSelector",
    value: ({get}) => {
        const networkAtomCount = get(networkAtom);
        const jobsAtomCount = get(jobsAtom);
        const messagingAtomCount = get(messagingAtom);
        const notificationsAtomCount = get(notificationsAtom);
        return networkAtomCount + jobsAtomCount + messagingAtomCount + notificationsAtomCount;
    }
})