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:
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.useRecoilValue : The task of this hook is to only read the current value of the atom, you cannot update the value.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;
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;
}
})