React – What is Recoil?

Recoil is a shared state between components

How to create shared state between components (Atom)?

useRecoilState is like useState but useRecoilState can be used to access/ update state from different components

// Define a shared state
const fontSizeState = atom({
  key: 'fontSizeState',
  default: 14,
});

// FontButton component accesses this state and update it 
function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  return (
    <button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
      Click to Enlarge
    </button>
  );
}

// Text component is also able to access this state (or of course to update it too)
function Text() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  return <p style={{fontSize}}>This text will increase in size too.</p>;
}

How to create read only shared state basing on Atom state?

Use selectors. Selector takes Atom state as input and returns a formatted value as output.

// fontSizeLabelState selector takes fontSizeState as input 
// fontSizeLabelState returns a formatted font size label as output
const fontSizeLabelState = selector({
  key: 'fontSizeLabelState',
  get: ({get}) => {
    const fontSize = get(fontSizeState);
    const unit = 'px';

    return `${fontSize}${unit}`;
  },
});

// FontButton component accesses fontSizeLabelState selector
// Clicking on the button does two things: 
//       - increases the font size of the button
//       - while also updating the font size label
function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  const fontSizeLabel = useRecoilValue(fontSizeLabelState);

  return (
    <>
      <div>Current font size: ${fontSizeLabel}</div>

      <button onClick={() => setFontSize(fontSize + 1)} style={{fontSize}}>
        Click to Enlarge
      </button>
    </>
  );
}

How to get Recoil state in a custom hook?

Since recoil only subscribe and update those values inside react component, useRecoilState and useRecoilValue hook don’t work properly in custom hooks.

We will have to update the value by ourselves.

import { useEffect, useRef } from 'react';
import { useRecoilState } from 'recoil';
import { someAtom } from './recoilstates/someState';

const yourCustomHook = () => {
  const [someState, setSomeState] = useRecoilState(someAtom);
  const latestSomeState = useRef(someState);

  useEffect(()=> {
    latestSomeState.current = someState;
  },[someState]);

  // I use useEffect here as an example,
  // custom hook can contain any React hooks
  useEffect(()=>{
    // your custom hook logic here
    // use latestSomeState.current for latest value
  });
}

Be the first to comment

Leave a Reply

Your email address will not be published.


*