DEV Community

Safal Bhandari
Safal Bhandari

Posted on

Selectors in Recoil: A Complete Guide

In Recoil, selectors are pure functions that let you derive, transform, or filter state from atoms (or even other selectors). They don’t store data themselves — instead, they compute it based on existing state, ensuring your UI stays in sync without redundant manual updates.


Why Use a Selector?

Imagine you have an atom that stores raw data (e.g., a list of products). You might need:

  • Only filtered products
  • A computed total price
  • A transformed version of the data

Instead of computing these values in multiple components (which would repeat logic), you centralize the logic inside a selector.


How Selectors Work

  • A selector is created using the selector function from Recoil.
  • It has a get function to read and compute state.
  • Optionally, it can have a set function to modify underlying atoms when the selector is written to.

Basic Example:

import { atom, selector } from 'recoil';

export const productListState = atom({
  key: 'productListState',
  default: [
    { name: 'Laptop', price: 1000 },
    { name: 'Phone', price: 500 },
  ],
});

export const totalPriceSelector = selector({
  key: 'totalPriceSelector',
  get: ({ get }) => {
    const list = get(productListState);
    return list.reduce((sum, item) => sum + item.price, 0);
  },
});
Enter fullscreen mode Exit fullscreen mode

Here:

  • productListState is our atom (raw data).
  • totalPriceSelector derives data (sum of prices).

Reading a Selector in a Component

Selectors behave just like atoms when used in components:

import { useRecoilValue } from 'recoil';
import { totalPriceSelector } from './store';

function CartTotal() {
  const total = useRecoilValue(totalPriceSelector);
  return <div>Total Price: ${total}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Writable Selectors

Selectors can also be writable — meaning you can both read and write.
Example:

export const textState = atom({
  key: 'textState',
  default: '',
});

export const uppercaseTextSelector = selector({
  key: 'uppercaseTextSelector',
  get: ({ get }) => get(textState).toUpperCase(),
  set: ({ set }, newValue) => {
    set(textState, newValue.toLowerCase());
  },
});
Enter fullscreen mode Exit fullscreen mode

Key Points to Remember

  • Pure Functions: Selectors should not have side effects; they should only depend on other atoms/selectors.
  • Automatic Caching: If the underlying atoms don’t change, the selector result is cached.
  • Derived State: Use selectors to avoid duplicating computed logic across multiple components.
  • Performance Friendly: They recalculate only when their dependencies change.

Top comments (0)