Post

Using Recoil for Front-end State Management

Using Recoil for Front-end State Management

This post was migrated from Tistory. You can find the original here.

While trying to figure out what to use for front-end state management, I came across Recoil, which seems to be used a lot like useState.

1
2
3
4
5
6
7
function App() {
  return (
    <RecoilRoot>
      <CharacterCounter />
    </RecoilRoot>
  );
}

Just wrap things loosely like this,

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

give it a state key and a default value,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function TextInput() {
  const [text, setText] = useRecoilState(textState);

  const onChange = (event) => {
    setText(event.target.value);
  };

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
      <br />
      Echo: {text}
    </div>
  );

and you can use it right away. The learning curve is close to zero — you can just use it without thinking too much.

1
2
3
4
5
6
7
8
const charCountState = selector({
  key: 'charCountState', // unique ID (with respect to other atoms/selectors)
  get: ({get}) => {
    const text = get(textState);

    return text.length;
  },
});

There’s also selector,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const filteredTodoListState = selector({
  key: 'FilteredTodoList',
  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;
    }
  },
});

and if you write it like this,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function TodoList() {
  // changed from todoListState to filteredTodoListState
  const todoList = useRecoilValue(filteredTodoListState);

  return (
    <>
      <TodoListStats />
      <TodoListFilters />
      <TodoItemCreator />

      {todoList.map((todoItem) => (
        <TodoItem item={todoItem} key={todoItem.id} />
      ))}
    </>
  );
}

you can use it this way too.

Here, a single result is derived from two pieces of state, and the selector re-runs whenever either one of them changes.

By skillfully combining several state values inside a selector, it seems possible to write components that are much more readable.

References

https://recoiljs.org/ko/docs/introduction/getting-started/#selector

https://recoiljs.org/docs/basic-tutorial/selectors/

This post is licensed under CC BY-NC 4.0 by the author.