React State Management Using Easy Peasy
Tags: javascript, webdev, react, easypeasy
Published: 2022-04-18 22:23:02

by [Fortune Ikechi](https://blog.openreplay.com/authors/fortune-ikechi)

According to the [documentation](https://easy-peasy.now.sh/docs/introduction/),

> Easy Peasy is an abstraction of Redux, providing a reimagined API that focuses on **developer experience**. It allows you to **quickly** and **easily** manage your state while leveraging strong **architectural guarantees.**
    
We’ll use Easy Peasy as the state manager of choice to build a note application that will help us learn how it works. 

## Introduction

In building React applications, one of the most important questions for developers includes managing the state effectively. In this tutorial, we will learn how to use [Easy Peasy](https://easy-peasy.now.sh/) to manage state in React applications. We will understand the core concepts of Easy Peasy and some use cases for it, why it should be used for your next application, and we’ll build a simple example. Easy Peasy is open source with more than 4.1k stars on [GitHub.](https://github.com/ctrlplusb/easy-peasy)

This tutorial will be beneficial to readers interested in learning how to manage state with Easy Peasy in their React applications or looking for alternatives to state management in a React application. This article requires a basic understanding of React and JavaScript. 

## What is Easy Peasy?

Easy Peasy is a state manager that works similar to Redux but with less code and complexity than Redux. Easy Peasy was built to provide the same performance as Redux and other state managers.

Core concepts of Easy Peasy include the following hooks and methods.

- **Store:** Similar to Redux, Easy Peasy requires a store powered by React Context, which will disclose the application state to certain parts of your application.
- **State:** This is an essential part of Easy Peasy because it uses the state or model to define your application store.
- **Thunk Action:** This is used in Easy Peasy to perform operations that are termed side effects, such as making an API call.
- **Action: Actions** used to update the application store. 
- **UseStoreState**: This is a custom hook from Easy Peasy that gives our components access to the application’s store state. 
- **UseStoreActions:** As the name implies, this hook gives our components access to the store’s actions. 
- **Provider**: Similar to Redux, Easy Peasy comes with a Provider method that exposes the store to our React app. This is done so our components will be able to consume the store with React hooks.

Easy Peasy can be installed using the command below. (We prefer using `yarn` to using `npm`.)

```
yarn add easy-peasy
```

## Why Easy Peasy?

Easy Peasy’s main objective is to improve state management for React developers and make for an easier way of managing application states with less code and boilerplate. Easy Peasy removes the abstractions of Redux and simplifies state management with a simpler process, making it easier for anyone to use in React applications.

Easy Peasy also supports React-Hooks-based APIs and Redux middleware such as Redux thunks out of the box. Easy Peasy can be set up to perform API requests as a side effect using thunk actions. Please see the API call below for an example of a request to delete a user and get a user by their `id`. 

```javascript
import {
  action,
  computed,
  createContextStore,
  thunk,
} from "easy-peasy";
import { deleteUser, getUserById } from "./user";

const UserStore = createContextStore({
  getUsers: thunk(async (actions) => {
    actions.setIsLoading();
    try {
      const { data } = await getUsers();
      actions.setUsers(data);
    } catch (e) {
      actions.setError(e);
    }
    actions.setIsLoading();
  }),
  getUserById: thunk(async (actions, id) => {
    actions.setIsLoading();
    try {
      const { data } = await getUserById(id);
      actions.setUser(data);
    } catch (e) {
      actions.setError(e);
    }
    actions.setIsLoading();
  }),
});

```

In the code block, we get users from the API using the `getUser` thunk and setting the user as our current state. We also did the same thing with the `deleteUser` method. 

## Easy Peasy vs. Redux/MobX/HookState

Like other state managers like Redux and MobX, Easy Peasy uses a single store to handle the application state, and it also uses actions as a source of data for the application store. It’s important to note that Easy Peasy uses Redux internally to manage state.

Unlike Redux and MobX, Easy Peasy requires little to no boilerplate code to work with. Easy Peasy uses [Immer](https://immerjs.github.io/immer/docs/introduction) under the hood, which gives developers the power to interact with data while keeping the benefits of the immutable data.

Easy Peasy allows developers to extend the application store using Redux middleware and other custom hooks to enhance performance.

Compared to React HookState, Easy Peasy offers more ease of managing and updating state with a single store and sharing information with components using custom hooks such as `useStoreState` and `useStoreAction`, which comes out of the box with Easy Peasy.

With its ease and zero boilerplate code, Easy Peasy can be used to manage state from simple React to-do applications to larger applications. Easy Peasy also provides support for TypeScript out of the box.

## Building Notes application with Easy Peasy 

Now that we know the core concepts of Easy Peasy, we’ll be building a notes application and managing the state with Easy Peasy. The app will allow users to add, delete and temporarily cancel a note using a toggle.

Without further ado, let’s start!

## Setting Up Your Environment

First, let’s create a bare React application. Write the code block below on your terminal. 

```
create-react-app easy-peasy-notes-app
```

The above code will create a bare React application using the [create-react-app](https://github.com/facebook/create-react-app) package. Move into the project directory and add the dependencies that we will need for our application.

```
cd easy-peasy-notes-app
yarn add easy-peasy uuid
```

In the above code block, we installed:

- **Easy-peasy:** our state manager for our application
- **uuid:** This is to create a unique string of notes for our application

Start the project server using the command below if you’ve done this. 

```
yarn start
```

Next, let’s create a `components` folder in our `src` directory. We will be creating three components and an app store for our application. 

## Creating an App Store

As mentioned above, Easy Peasy works with a `store` to hold the application state. With this, we can access the application store and update the state. We will need to set up a function to add, toggle, and delete notes in our application in the store. To create our app store, first create a `Store.js` file in our project’s `src` directory, next let’s add logic to our store.

```javascript
import { action } from "easy-peasy";
import uuid from "uuid";

export default {
  notes: [],
  setNote: action((state, notes) => {
    state.notes = notes;
  }),
  addNote: action((state, note) => {
    note.id = uuid.v4();
    state.notes.push(note);
  }),
  toggleNote: action((state, id) => {
    state.notes.map((note) => {
      return note.id === id
        ? (note.completed = !note.completed)
        : note;
    });
  }),
  removeNote: action((state, id) => {
    state.notes = state.notes.filter(
      (note) => note.id !== id
    );
  }),
};

```

We imported `actions` from `easy-peasy` in the code above. The actions will be used to update our application store. We imported `uuid` to give unique `ids` to our notes when they are created. We initialized notes as an empty array object and created a function `setNote` that takes in the state and note parameters and sets the current note as the value for `state.notes`. The `addNote` function takes in two parameters: an initial `state` and a `note`. We assign the note `id` to one automatically provided by `uuid.v4()` and push the new note into the `state.notes` array. The `toggleNote` parameter takes in the state and `id` parameters and uses the native JavaScript [map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) object to cross off the completed notes by toggling the value of `note.completed`, the `removeNote` object deletes a note using the [filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) object. 

In the next section, we will use the logic above to create our application’s component. 

## Building the Note component

Here, we will build our note component, the primary component for how each list will look on our application. Let’s create a components folder in our project’s `src` directory and create a new file, `Note.jsx`. Inside it, write the code block below.

```javascript
import React from "react";
import { useStoreActions } from "easy-peasy";

const Note = ({ note }) => {
  const { completed } = note;
  const removeNote = useStoreActions(
    (actions) => actions.removeNote
  );
  const toggleNote = useStoreActions(
    (actions) => actions.toggleNote
  );
  return (
    <li className="d-flex justify-content-between align-items-center mb-2">
      <span
        className="h2 mr-2"
        style={{
          textDecoration: completed ? "line-through" : "",
          cursor: "pointer",
        }}
        onClick={() => toggleNote(note.id)}
      >
        {note.title}
      </span>
      <button
        onClick={() => removeNote(note.id)}
        className="btn btn-danger btn-lg"
      >
        &times;
      </button>
    </li>
  );
};

export default Note;

```

Here, the `useStoreActions` hook from easy-peasy gives our `Note` component access to the actions in the store: in this case, `toggleNote` to cross off a note as completed and `addNote` to add a new note. We returned the `li` tag, which contains the new notes. 

Next, we add a delete button for our application. Similar to toggling a note, we add an `onClick` event that takes in the `removeNote` action. If we did this correctly, our app should look like the image below.

![Notes component](https://blog.openreplay.com/static/b422fd0fe4716c1775b50e8b2f34e3f1/778aa/image01.png)

## Building Notes component

This component will act as a render for our notes. Here we will add a header component for our application name and render all our notes in this component, let’s do that below.

```javascript
import React from "react";
import { useStoreState } from "easy-peasy";
import Note from "./Note";
const Notes = () => {
  const notes = useStoreState((state) => state.notes);
  return (
    <>
      <h1 className="display-4">Notes</h1>
      {notes.length === 0 ? (
        <h2 className="display-3 text-capitalize">
          Please add note
        </h2>
      ) : (
        notes.map((note) => (
          <Note key={note.id} note={note} />
        ))
      )}
    </>
  );
};

export default Notes;
``` 

Here, we import the `[useStoreState](https://easy-peasy.now.sh/docs/api/use-store-state.html)` hook from easy-peasy. The `useStoreState` grants our component access to the store’s state. Next, we create a functional component, `notes`, and using the `useStorestate`, we assign `notes` to the state of the application found on the store. As an [edge case](https://www.quora.com/What-is-an-edge-case-when-programming) using a ternary operator, we will drop a text for the user to add a note if they haven’t and render a note if they did. You can learn more about ternary operators [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator).

## Building NotesForm Component

This component will be the bulk of our application. Here we will handle submitting our notes and setting them as the updated value of our application state. Let’s build the component below.

```javascript
import React, { useState } from "react";
import { useStoreActions } from "easy-peasy";

const NotesForm = () => {
  const [title, setTitle] = useState("");
  const [err, setErr] = useState(false);
  const addNote = useStoreActions(
    (actions) => actions.addNote
  );
  const handleSubmit = (e) => {
    e.preventDefault();
    if (title.trim() === "") {
      setErr(true);
    } else {
      setErr(false);
      addNote({
        title,
        completed: false,
      });
    }
    setTitle("");
  };
  return (
    <>
      <form
        onSubmit={handleSubmit}
        className="d-flex py-5 form-inline"
      >
        <input
          type="text"
          placeholder="Add Todo Title"
          value={title}
          className="form-control mr-sm-2 form-control-lg"
          onChange={(e) => setTitle(e.target.value)}
        />
        <button
          type="submit"
          className="btn btn-success btn-lg rounded"
        >
          Add Note
        </button>
      </form>
      {err && (
        <div className="alert alert-dismissible alert-danger">
          <button
            type="button"
            className="close"
            data-dismiss="alert"
            onClick={() => setErr(false)}
          >
            &times;
          </button>
          <strong>Oh oh!</strong>{" "}
          <span className="alert-link">
            please add a valid text
          </span>
        </div>
      )}
    </>
  );
};

export default NotesForm;
```
    
In this component, to access our project’s action objects in the store, we imported the `useStoreActions` and initialized the `addNote` action for adding a note in our component. Next, we created an input form that includes input for adding notes, submitting a note to be added, and a button for alert for when a user tries to add an empty note using the input. 

The final act will be to set up our `App.js` file and wrap up our application using a `Provider` and restart our server to see our final application. Let’s do that in the code block below. 

```javascript
import React from "react";
import "./styles.css";
import Notes from "./components/Notes";
import NotesForm from "./components/NotesForm";

import { StoreProvider, createStore } from "easy-peasy";
import store from "./Store";

const Store = createStore(store);
function App() {
  return (
    <StoreProvider store={Store}>
      <div className="container">
        <NotesForm />
        <Notes />
      </div>
    </StoreProvider>
  );
}

```

Here, we import the `StoreProvider` and `createStore`. The `StoreProvider` exposes the `store` to our application so that our components can consume the store using hooks. The `createStore`, similar to Redux, creates a global `store` based on the models we’ve provided. Next, we wrapped our App component using the store as a parameter of the `StoreProvider`. 

Once done correctly, our app should look like the image below.

![Easy Peasy note application](https://blog.openreplay.com/static/311336c0256ecf831164e0d6ddd1eb39/e1280/image02.png)

## Open Source Session Replay

_[OpenReplay](https://github.com/openreplay/openreplay) is an open-source alternative to FullStory and LogRocket. It gives you full observability by replaying everything your users do on your app and showing how your stack behaves for every issue. OpenReplay is self-hosted for full control over your data._

![replayer.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1647097041609/Qi6sMOaaB.png)

_Happy debugging for modern frontend teams - [start monitoring your web app for free](https://github.com/openreplay/openreplay)._

## API Request with Easy Peasy

In this section, we will look at handling API requests with Easy Peasy. To better understand this, we will be building a currency converter using React, TypeScript, and Easy Peasy to manage state. In our application, users should be able to convert dollars to any currency. Users can input the amount they’d like to convert and the currency they’re converting to. 

First, we will create a react app using the command below. We will add typescript support and reactstrap for styling.

```
create-react-app currency-converter
yarn add @testing-library/jest-dom @testing-library/react @testing-library/user-event @types/jest @types/node @types/react @types/react-dom axios bootstrap easy-peasy reactstrap typescript 
```

For TypeScript support, create a `tsconfig.json` file in the root directory of our project and copy the code block below into it.

```
{
  compilerOptions: {
    target: "es5",
    lib: ["dom", "dom.iterable", "esnext"],
    allowJs: true,
    skipLibCheck: true,
    esModuleInterop: true,
    allowSyntheticDefaultImports: true,
    strict: true,
    forceConsistentCasingInFileNames: true,
    noFallthroughCasesInSwitch: true,
    module: "esnext",
    moduleResolution: "node",
    resolveJsonModule: true,
    isolatedModules: true,
    noEmit: true,
    jsx: "react-jsx",
  },
  include: ["src"],
};
```

After we’ve added the code above, to finish TypeScript configuration for our project, create a new file in the root directory of our project named `react-app-env.d.ts`. This file will reference the type of react-scripts in our project. You can learn more about it [here.](https://www.sitepoint.com/react-with-typescript-best-practices/#:~:text=json%20is%20the%20TypeScript%20configuration,like%20allowing%20for%20SVG%20imports.)

```
/// <reference types="react-scripts" />
```

## Building Our App’s Store

To get started on our project properly, in the `src` directory of your project, create a `store` folder for our app’s store and inside it, create two files, `index.ts` and `typehook.ts.` Our `index.ts` file will contain our TypeScript interfaces for our API functions. Our application will store actions while our `typehook.ts` will contain Typed hooks from Easy Peasy. We will create interfaces for our API requests in the code block below.

```javascript
import {
  createStore,
  Action,
  action,
  Thunk,
  thunk,
} from "easy-peasy";
import axios from "../axios";

export interface ICurrency {
  currency_name: string;
  currency_code: string;
  decimal_units: string;
  countries: string[];
}
interface IAllCurrencies {
  data: ICurrency[];
  updateResult: Action<IAllCurrencies, ICurrency[]>;
  getAllCurrencies: Thunk<IAllCurrencies>;
}
interface ICurrencyRates {
  rates: { [key: string]: string };
  updateRates: Action<ICurrencyRates, any>;
  getCurrencyRates: Thunk<ICurrencyRates>;
}
interface IConversion {
  data: {
    to: string,
    amount: string,
  };
  updateTo: Action<IConversion, string>;
  updateAmount: Action<IConversion, string>;
}
export interface IStore {
  allCurrencies: IAllCurrencies;
  currencyRates: ICurrencyRates;
  conversion: IConversion;
}

const store =
  createStore <
  IStore >
  {
    allCurrencies: {
      data: [],
      updateResult: action((state, payload) => {
        state.data = Object.values(payload);
      }),
      getAllCurrencies: thunk(async (actions) => {
        try {
          const res = await axios.get(`/currencies`);
          actions.updateResult(res?.data?.response?.fiats);
        } catch (error) {
          console.log(error);
        }
      }),
    },
    currencyRates: {
      rates: {},
      updateRates: action((state, payload) => {
        state.rates = payload;
      }),
      getCurrencyRates: thunk(async (actions) => {
        try {
          const res = await axios.get(`/latest`);
          actions.updateRates(res?.data?.response?.rates);
        } catch (error) {
          console.log(error);
        }
      }),
    },
    conversion: {
      data: {
        to: "",
        amount: "",
      },
      updateTo: action((state, payload) => {
        state.data.to = payload;
      }),
      updateAmount: action((state, payload) => {
        state.data.amount = payload;
      }),
    },
  };

export default store;
```

Here, we created interfaces that define the contract on our properties. For example, in `ICurrency` we enforced the name, code, decimal units, and countries to be of type `string`. In `IAllCurrencies`, we define the data we’ll get from the API as an array containing the object we’ve defined in `ICurrency`. We also enforce our `updateResult` work based on the interface of `IAllCurrencies` and accept a payload of `ICurrency` in an array. The `getAllCurrencies` method uses a [Thunk](https://easy-peasy.now.sh/docs/api/thunk.html) to perform asynchronous functions. We have added an interface for `ICurrencyRates`. We defined rates to take in objects with keys that must be strings and accept a string payload. `updateRates` will work with the data and any data type. `getCurrencyRates` uses Thunk to perform asynchronous functions with the data returned. 

To create a store, we first called the easy-peasy store. In our case, we structured the store to use the `IStore` interface. Next, we called the `allCurrencies` object from the `IStore`. In it, we will receive the data as an array. Like Redux, to update a state in easy peasy, you’d use an action. We defined the action `updateResult`, which acts as a [reducer](https://easy-peasy.now.sh/docs/api/reducer.html). It takes in our current state and the user’s payload, and sets the current state using the values we get from the user’s payload. You can learn more about updating the [store](https://redux.js.org/api/createstore) and [createStore](https://easy-peasy.now.sh/docs/api/create-store.html).

To `getAllCurrencies`, we performed an async operation using `axios` to get all currencies and use actions from setting the data as a response. We wrapped the full application with a `try…catch` method in case of errors. We performed similar functions in our `currencyRate` object, updating the state with an action, performing an async operation to get the latest rates from the API, and setting the state using the data we receive.

The Conversion object converts the amount inputted by the user from dollars to any currency the user chooses. We defined an action that updates and renders the amount converted to the user to display the amount. 

## Building our Store Type Hooks 

When using Easy Peasy with TypeScript, hooks are often recommended to have types. This is usually done with interfaces defined in the project store. In this section, we will add types to the hooks we will be using in our application. To do this, inside our store directory, create a new file called `typehook.ts`. Inside it, write the code block below.

```javascript
import { createTypedHooks } from "easy-peasy";
import { IStore } from "./index";

const typedHooks = createTypedHooks<IStore>();

export const useStoreActions = typedHooks.useStoreActions;
export const useStoreDispatch = typedHooks.useStoreDispatch;
export const useStoreState = typedHooks.useStoreState;
```

In the code block above, we are adding types to our `useStoreActions`, `useStoreDispatch`, and our `useStoreState` hooks. With this, we are configuring it to the interfaces we’ve defined in our `IStore`. By doing this, whatever actions we are dispatching here will come from actions from the store.

## Building Header Component

In this section, we will add a `Header` to our application. The application header will contain our header, input fields for the user to add the amount, and the currency they wish to convert. First, we’ll create a `components` folder in our’ src’ directory. Inside that folder, we’ll create a `header` folder, which will contain a `header.tsx` file. Let’s add the logic for this.

```javascript
import { useState } from "react";
import {
  Button,
  Form,
  FormGroup,
  Input,
  Jumbotron,
} from "reactstrap";
import { ICurrency } from "../../store";
import {
  useStoreState,
  useStoreActions,
} from "../../store/typehook";

const Header = () => {
  const allCurrencies = useStoreState(
    (state) => state.allCurrencies.data
  );
  const setAmountToConvert = useStoreActions(
    (actions) => actions.conversion.updateAmount
  );
  const setCurrencyToConvertTo = useStoreActions(
    (actions) => actions.conversion.updateTo
  );
  const [to, setTo] = useState<string>("");
  const [amount, setAmount] = useState<string>("");

  const onSubmitHandler = (e: {
    preventDefault: () => void;
  }) => {
    e.preventDefault();
    to && amount && setAmountToConvert(amount);
    to && amount && setCurrencyToConvertTo(to);
  };
};
```

We imported the `ICurrency` object from our store in the code block above. We also imported `useStoreState` and `useStoreActions` from our custom typed hooks. 

We initialized our Header as a functional component. Next, we create a constant `allCurrencies` to get the state of `allCurrencies` in our store. With `setAmountToConvertTo`, we called an action. The action we called is the `updateAmount` action from the store. 

Using React `useState`, we defined the state we wanted to update. We added a `<string>` to let our app know that the state we are updating and defining is of string type. 

We created a function `onSubmitHandler` to handle submissions, which converts the amount and currency the user input on the submission. 

To finish our Header component, let’s render the input fields using react strap for our components and bootstrap for styling. We will append the code block below to the functions defined at the beginning of this section.

```javascript
return (
  <div className="text-center">
    <Jumbotron fluid>
      <h1 className="display-4">Currency Converter</h1>
      <div className="w-50 mx-auto">
        <Form id="my-form" onSubmit={onSubmitHandler}>
          <FormGroup className="d-flex flex-row mt-5 mb-5">
            <Input
              type="number"
              value={amount}
              onChange={(e) => setAmount(e.target.value)}
              placeholder="Amount in Number"
            />
            <Input
              type="text"
              value="from USD ($)"
              className="text-center w-50 mx-4"
              disabled
            />
            <Input
              type="select"
              value={to}
              onChange={(e) => setTo(e.target.value)}
            >
              <option>Converting to?</option>
              {allCurrencies.map((currency: ICurrency) => (
                <option
                  key={currency?.currency_code}
                  value={currency?.currency_code}
                >
                  {currency?.currency_name}
                </option>
              ))}
            </Input>
          </FormGroup>
        </Form>
        <Button
          color="primary"
          size="lg"
          block
          className="px-4"
          type="submit"
          form="my-form"
        >
          Convert
        </Button>
      </div>
    </Jumbotron>
  </div>
);
```

Here, we built the input fields for our application, one for the amount to be converted and the currency. If done correctly, our app should look similar to the image below.

![Header component](https://blog.openreplay.com/static/a4d67c6115a0f0b3149a294797e96512/0fcc3/image03.png)

## Adding Currency API

To get the latest conversion rates and countries, We will be using the `rapid API` currency API. First, create a new folder `axios` in our `src` directory. Create a new file, `index.tsx` inside this folder. 

Next is to visit [Rapid API](https://rapidapi.com/citeamaccount/api/currencyscoop) and sign up to get an APIKey when we do this, paste your API base URL and API keys inside our `index.tsx` in the format below 

```javascript
import axios from "axios";
export default axios.create({
  baseURL: "https://currencyscoop.p.rapidapi.com",
  headers: {
    "x-rapidapi-key": "your api key goes here",
    "x-rapidapi-host": "currencyscoop.p.rapidapi.com",
  },
});
```

Let’s configure our `App.tsx` in the next section to complete our application. 

## Configuring App.tsx 

First, We will import all our actions and states from `typedhooks` and initialize them in our `App.tsx`. Let’s do that below.

```javascript
    import { useEffect } from "react";
import {
  useStoreActions,
  useStoreState,
} from "./store/typehook";
import Header from "./components/header/Header";

const App = () => {
  const getAllCurrencies = useStoreActions(
    (actions) => actions.allCurrencies.getAllCurrencies
  );
  const getCurrencyRates = useStoreActions(
    (actions) => actions.currencyRates.getCurrencyRates
  );
  const currencyRates = useStoreState(
    (state) => state.currencyRates.rates
  );
  const amountToConvert = useStoreState(
    (state) => state.conversion.data.amount
  );
  const currencyConvertingTo = useStoreState(
    (state) => state.conversion.data.to
  );

  useEffect(() => {
    getAllCurrencies();
    getCurrencyRates();
  }, [getAllCurrencies, getCurrencyRates]);

  const equivalence = () => {
    const val = Number(currencyRates[currencyConvertingTo]);
    return val * parseInt(amountToConvert);
  };

  return (
    <div
      style={{ background: "#E9ECEF", height: "100vh" }}
      className="container-fluid"
    >
      <Header />
      <div className="w-50 mx-auto">
        {amountToConvert && currencyConvertingTo ? (
          <h2>Result:</h2>
        ) : null}
        {amountToConvert ? (
          <h3>
            ${amountToConvert} = {equivalence()}
          </h3>
        ) : null}
      </div>
    </div>
  );
};

export default App;
```

Similar to what we did in our `typedhooks` file, in the code block above, we initialized all our store functions such as the `getAllCurrencies` and `getCurrencyRates` in this component. We used React `useEffect` hook to call the actions `getAllCurrencies` and `getCurrencyRates` from our store. 

Next, we initialized a function `equivalence` that converts the currency rates from an object and returns the value we get from the API, and multiplies it by the amount inputted by the user as an integer. 

To conclude, we used bootstrap and react strap to build components for our input. If done correctly, our app should look like this. 

![easy peasy currency converter](https://blog.openreplay.com/static/0699ebe7954720ea42b1c2f8bfefbcac/487f0/image04.png)

## Conclusion

In this article, we learned about Easy Peasy, a state manager for React applications focused on providing a better experience for developers. We also went through the process of creating a notes application using Easy Peasy to manage the state. We also detailed the pros of using easy-peasy to manage state for your next application. Have fun using Easy Peasy for your next React application!


## Resources

The notes app can be found on [Codesandbox](https://codesandbox.io/s/awesome-meninsky-kjco6?file=/src/components/NotesForm.jsx), and the currency converter is [here](https://codesandbox.io/s/dry-hooks-9qio1?file=/src/App.tsx). 

- [Easy Peasy docs](https://easy-peasy.now.sh/docs/introduction/)
- [Easy Peasy GitHub page](https://github.com/ctrlplusb/easy-peasy)
- [Easy Peasy The React Redux Wrapper](https://itnext.io/easy-peasy-the-react-redux-wrapper-b31a5911c5e3)
- [Easy Peasy global state with React Hooks](https://medium.com/@ctrlplusb/easy-peasy-global-state-in-react-w-hooks-421f5bf827cf)
- [Easy Peasy TypeScript](https://easy-peasy.now.sh/docs/tutorials/typescript.html)