Recoil with React and TypeScript
Tags: typescript, javascript, react
Published: 2021-01-13 19:49:47

Recoil is yet another state management library for React, I just wanted to give it a try so I decided to re-create [my other post's sample](https://dev.to/sirwanafifi/mobx-with-react-and-typescript-58bf) (MobX with React and TypeScript
) in Recoil.

Recoil has pretty simple API to work with, the functionality is the same as other state management library but the names are different, Recoil seems to be a bit better in terms of code boilerplate. It has two important concepts to know:

- Atoms: Atoms are units of state. They're updateable and subscribable: when an atom is updated, each subscribed component is re-rendered with the new value. They can be created at runtime, too. Atoms can be used in place of React local component state. If the same atom is used from multiple components, all those components share their state.

- Selector: A selector is a pure function that accepts atoms or other selectors as input. When these upstream atoms or selectors are updated, the selector function will be re-evaluated. Components can subscribe to selectors just like atoms, and will then be re-rendered when the selectors change.

# Creating a Simple Todo App with Recoil and React
let's create a simple todo app using React:

```ts
mkdit recoil_sample && cd recoil_sample
npx create-react-app . --typescript
yarn add bootstrap --save
```

Now go to `index.tsx` and import `bootstrap.css`:

```ts
import "bootstrap/dist/css/bootstrap.css"
```

Now we'll install the needed dependencies:

```ts
yarn add recoil uuid @types/uuid --save
```

Now let's create a store inside the project 

```ts
import { atom, selector } from "recoil";

export interface Todo {
  id?: string;
  title: string;
  completed: boolean;
}

export const todosState = atom({
  key: "todos",
  default: [] as Todo[],
});

export const infoValue = selector({
  key: "infoValue",
  get: ({ get }) => ({
    total: get(todosState).length,
    completed: get(todosState).filter((todo) => todo.completed).length,
    notCompleted: get(todosState).filter((todo) => !todo.completed).length,
  }),
});

```

Now create a new folder called components in the `src` directory and add `TodoAdd.tsx` and `TodoList.tsx`:

### TodoAdd

```ts
import { useState } from "react";
import { useRecoilState, useRecoilValue } from "recoil";
import { infoValue, todosState } from "../store";
import { v4 } from "uuid";

const AddTodo = () => {
  const [title, setTitle] = useState("");
  const [todos, setTodos] = useRecoilState(todosState);
  const info = useRecoilValue(infoValue);

  return (
    <>
      <div className="alert alert-primary">
        <div className="d-inline col-4">
          Total items: &nbsp;
          <span className="badge badge-info">{info.total}</span>
        </div>
        <div className="d-inline col-4">
          Finished items: &nbsp;
          <span className="badge badge-info">{info.completed}</span>
        </div>
        <div className="d-inline col-4">
          Unfinished items: &nbsp;
          <span className="badge badge-info">{info.notCompleted}</span>
        </div>
      </div>
      <div className="form-group">
        <input
          className="form-control"
          type="text"
          value={title}
          placeholder="Todo title..."
          onChange={(e) => setTitle(e.target.value)}
        />
      </div>
      <div className="form-group">
        <button
          className="btn btn-primary"
          onClick={(_) => {
            setTodos([...todos, { id: v4(), title: title, completed: false }]);
            setTitle("");
          }}
        >
          Add Todo
        </button>
      </div>
    </>
  );
};

export default AddTodo;
```

### TodoList

```ts
import { useRecoilState } from "recoil";
import { todosState } from "../store";

const TodoList = () => {
  const [todos, setTodos] = useRecoilState(todosState);

  const toggleTodo = (id: string) =>
    setTodos(
      todos.map((todo) => {
        if (todo.id === id) {
          return {
            ...todo,
            completed: !todo.completed,
          };
        }
        return todo;
      })
    );
  const removeTodo = (id: string) =>
    setTodos(todos.filter((todo) => todo.id !== id));

  return (
    <>
      <div className="row">
        <table className="table table-hover">
          <thead className="thead-light">
            <tr>
              <th>Title</th>
              <th>Completed?</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {todos.map((todo) => (
              <tr key={todo.id}>
                <td>{todo.title}</td>
                <td>{todo.completed ? "✅" : ""}</td>
                <td>
                  <button
                    className="btn btn-sm btn-info"
                    onClick={(_) => toggleTodo(todo.id!)}
                  >
                    Toggle
                  </button>
                  <button
                    className="btn btn-sm btn-danger"
                    onClick={(_) => removeTodo(todo.id!)}
                  >
                    Remove
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </>
  );
};

export default TodoList;
```

That's it, now you can run the project and manage your todo items:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/dkkqq7tht0qa1yylh09t.png)

[Here](https://github.com/SirwanAfifi/recoil_sample)'s the source for the project.