Recoil

Get Started

npm install recoil

Introduction

  • Recoil is a state management library developed by facebook

  • Similar with context, but it can pass multiple state, but also re-render for children who subscribe for the state

Atom

  • It is a state which is used to share to children

import {
  RecoilRoot,
  atom,
  selector
} from 'recoil';

const textState = atom({
  key: 'textState', // unique ID (with respect to other atoms/selectors)
  default: 'test', // default value (aka initial value)
});

function App() {
  return (
    <RecoilRoot>
       <TextInput  textState={textState}/>
  </RecoilRoot>
  );
  • We can change the value just like useState

import React from 'react'
import {useRecoilState} from "recoil";


function TextInput({textState}:any) {
    const [text, setText] = useRecoilState<string>(textState);
  
    const onChange = (event:any) => {
      setText(event.target.value);
    };
  
    return (
      <div>
        <input type="text" value={text} onChange={onChange} />
        <br />
        Echo: {text}
      </div>
    );
  }

export default TextInput

Selector

  • It is a pure function that take the atom as a input

import React from 'react';
import {
  RecoilRoot,
  atom,
  selector
} from 'recoil';
import CharCount from './CharCount';
import Test from './Test';
const textState = atom({
  key: 'textState', // unique ID (with respect to other atoms/selectors)
  default: 'test', // default value (aka initial value)
});

const charCountState = selector({
  key: 'charCountState', // unique ID (with respect to other atoms/selectors)
  get: ({get}) => {
    const text = get(textState);
    return text.length;
  },
});

function App() {
  return (
    <RecoilRoot>
       <TextInput  textState={textState}/>
        <CharCount charCountState={charCountState}/>
        <Test/>
  </RecoilRoot>
  );
}
  • The return value of selector cannot be change directly, so it is recommended to use useRecoilValue to get the return value only

import React from 'react'
import {useRecoilValue} from "recoil";
const CharCount = ({charCountState}:any) => {
    const count = useRecoilValue<number>(charCountState);

  return <>Character Count: {count}</>;
}

export default CharCount

Data Fetching

  • Data Fetching is mostly done on selector

const userState = selector({
  key: "userState",
  get: async({get})=>{
    try{
      const res = await axios.get(`https://jsonplaceholder.typicode.com/users/${get(idState)}`);
      return res.data.name;
    }
    catch(error){
      return "failed";
    }
  }
})
  • Data Fetching can be used with react suspense to show loading

const userState = selector({
  key: "userState",
  get: async({get})=>{
    try{
      const res = await axios.get(`https://jsonplaceholder.typicode.com/users/${get(idState)}`);
      return res.data.name;
    }
    catch(error){
      return "failed";
    }
  }
})

function App() {

  return (
    <RecoilRoot>
        <React.Suspense fallback={<div>Loading</div>}> 
          <UserDisplay userState={userState}/>
        </React.Suspense> 
  </RecoilRoot>
  );
}

export default App;
  • But also used show loading by using hook

import React from 'react'
import { useRecoilValue, useRecoilValueLoadable } from 'recoil'

interface Props{
    userState:any;
}

const UserDisplay:React.FC<Props> = ({userState}) => {
    const user = useRecoilValueLoadable<any>(userState);
    if(user.state === "loading")
        return <div>Loading</div>
        return (
            <div>
                {user.contents}
            </div>
        )
}

export default UserDisplay
  • Data Fetching can also take variable as a parameter on api calling instead of atom

const toDoState = selectorFamily({
  key: 'toDo',
  get: id => async() => {
    try{
      const res = await axios.get(`https://jsonplaceholder.typicode.com/todos/${id?.toString()}`);
      return res.data;
    }
    catch(error){
      return "failed";
    }
  }
})
import React from 'react'
import { useRecoilValueLoadable } from 'recoil'

interface Props{
    toDoId:number;
    toDoState: any;
}

const ToDoItem:React.FC<Props> = ({toDoId,toDoState}) => {
    //put the id as variable to selector
    const toDo = useRecoilValueLoadable<any>(toDoState(toDoId));
    if(toDo.state === "loading")
    return <div>Loading</div>
    return (
        <div>
            {toDo.contents.title}
        </div>
    )
}

export default ToDoItem;

Reference

Last updated

Was this helpful?