loading...

Trying Out Recoil - Facebooks New React State Management Library

muddybootscode profile image Michael Porter ・3 min read

Recently pretty much out of the blue we've had the Facebook team's new React state management library, Recoil, dropped on us at React Europe. You can watch here as Dave McCabe, breaks down the new library and it's features. He does an excellent job of explaining the types of the problems that the library is trying solve and in the video he demos a neat looking canvas application. After watching the video I wanted to try my hand at the building a similar app with React, Recoil, and D3.js.

To get started all you need to do is spin up a create-react-app and then add recoil to the project at the root. Like so:

import { RecoilRoot } from 'recoil';

<RecoilRoot>
  <App />
</RecoilRoot>

This will give you the ability to access recoil elements anywhere in your application.

To begin with, the most basic elements of Recoil are called atoms. You create an atom to represent a piece of Recoil state:

import { atom } from 'recoil';

const newAtom = atom({
   key: 'someUniqueKey',
   default: {}
})

You can then use Recoil's many different hook methods to use the atom's value anywhere in your application that's wrapped by the RecoilRoot. Almost all of the hooks will be familiar to anyone who's used React Hooks but you'll see some changes such as, useRecoilValue, useSetRecoilState which allow you to purely consume the Atom's state or provide a callback function to manipulate the Atom's strength. This takes a little getting use to vs the normal:

const [value, setValue] = useState(''):

That you see in regular react hooks but to me it's a welcome change that allows you to be very specific with what you're calling and how.

In addition to Atoms, Recoil brings with it Selectors which allow you go manipulate the state of atoms and return derived state. Using an example directly from the Recoil docs:

const filteredTodoListState = selector({
  key: 'filteredTodoListState',
  get: ({get}) => {
    const filter = get(todoListFilterState);
    const list = get(todoListState);

    switch (filter) {
      case 'Show Completed':
        return list.filter((item) => item.isComplete);
      case 'Show Uncompleted':
        return list.filter((item) => !item.isComplete);
      default:
        return list;
    }
  },
});

You can see that selector allows you the ability to get the value of an Atoms state, manipulate it, and then return a new value as derived state. While I didn't make use of this in my demo app, I'm going to try to do more with it in the future. Speaking of which.

You can find my demo app here.
Alt Text

The app allows you to create D3 element circles and squares and then manipulate them in via a simple interface. There's a link provided to the github repo on the page where you can check out the code but the basics are I use Recoil to create individual Atoms for each circle and square that you create. The Atoms are simple:

export const circleWithID = (id) => {
    return (
        atom({
            key: `item${id}`,
            default: {
                id,
                cx: 50,
                cy: 50,
                r: 15,
                fill: "#3942e0",
                offset: {

                }
            }

        })
    )
}

This provides me a default circle and I can then retrieve it no matter where from anywhere in the application with the unique key or identifier:

const [circleState, setCircleState] = useRecoilState(circleWithID(props.key))

In my demo I'm directly accessing the state of each item in two components. The SVG circle or square it's self, to manipulate the state while dragging and also the card that pops up with each component. This way the SVG element in fully interactive. If I wanted to create something to select and deal with multiple elements I could then create a selector and have access to selected items, something like this:

export const selectedItems = selector({
    key: 'selectedItems',
    get: ({get}) => {
        const items = get(itemList).map(i  => get(itemWithID(i)))
        return items.filter((item) => item.selected)
    }
});

At any rate, that's my small example of Recoil please check out the offcial docs and announcement video for more info.

Discussion

pic
Editor guide