CRUD Todo App - React and Redux-toolkit
Tags: webdev, react, redux, beginners
Published: 2023-04-18 02:25:09

## Introduction 

We’ll make a simple Todo-list app that performs all four CRUD (Create, Read, Update, Delete) operations- on the front-end, using React and Redux-Toolkit: [live link](https://todo-beige-tau.vercel.app/)

If you are familiar with Redux you can jump straight to the [Implementation](#implementation) 

What to get in this article:
- Why Redux?
- [Redux vs Redux-Toolkit](#redux-vs-reduxtoolkit)
- [How Redux Works](#how-redux-works)
- [Implementation](#implementation)
- [Helpful Links](#helpful-links) 

## Why Redux?
	
[Redux](https://redux.js.org) is a state management library, that helps centralize your application’s state and logic. It comes with a DevTool which makes it easy to trace when, where, why and how your application’s state changed.
It works with any UI layer and popularly used with Reactjs.
And you might be wondering, what’s the difference between Redux and Redux-Toolkit, let’s take a look at that.

## Redux vs ReduxToolkit

Redux is the core library for managing application state, while Redux-Toolkit is a companion library that provides additional utilities for working with Redux. You can use Redux on its own, but many developers find that Redux-Toolkit makes it even easier and more efficient to work with Redux even the Redux team recommends Redux-Toolkit as the approach for writing Redux logic, because it is a newer library that provides a set of utilities for working with Redux. It provides a simpler API for common tasks, as well as performance optimizations that can help to improve the performance of your application for example, the library uses Immer under the hood to provide immutable updates to the store, which can help to avoid unnecessary re-renders. Redux-Toolkit comes with functions for creating and managing Redux stores, as well as middleware for handling asynchronous actions, this can help to make your code more organized and maintainable. 
Simply put, Redux-Toolkit is designed to make it easier and more efficient to write Redux applications

## How Redux works

In Redux, you basically create an action and dispatch the action using the usedispatch hook.
Redux provides a predictable state container that helps manage the state of your application in a centralized manner, a store. A “store” is a container that retains your application’s global state, each component can access the store without having to send down props from one component to another. 

### The five major terminologies in Redux:
In major Redux applications you’ll find these major components working hand in hand. I will give brief explanation of each of these terminologies, it might not be clear enough, but follow through, while building our app it will become clearer. We’ll briefly discuss the main terminologies in a typical Redux app

- <b>Store:</b> A single source of truth that holds the entire state tree of your application.

- <b>Actions:</b> Actions are the medium used to send data from your application to your Redux store, they are plain JavaScript objects that represent an intention to change the state, they contain a type property that describes the action as well as a payload (an additional data necessary to carryout the action) to update the state. 

- <b>Reducers:</b> Reducers are Pure functions that take the current state and an action and return a new state. They should not modify the current state directly, but instead return a new state object.

- <p id="dispatch"><b>Dispatch:</b> To update the state, an action must be dispatched to the store using the `dispatch` function. This triggers the store to call the corresponding reducer function with the current state and the dispatched action. Just think of the `dispatch` function as `setState`</p>

- <p id="selector"><b>Selector:</b> To access data from the store. We do this by using the `useSelector` hook from react-redux </p>

Just think of Dispatch and Selector as

```javascript
const [name, setName] = useState("Grey");

// Dispatch (update the state)
setName("Dan");

// Selector (get the state)
console.log(name) 

```
---

## Implementation

### Installation
To get started, you only need two npm packages
`npm install @reduxjs/toolkit react-redux`

### Create a Redux Store
`src/redux/store.js`

```javascript
import { configureStore } from '@reduxjs/toolkit';

export const store = configureStore({
  reducer:{},
});
```

### Add the Redux Store to Index.js parent file

`src/index.js`
```javascript
import { Provider } from 'react-redux';
import { store } from './redux/store';

<Provider store={store}>
   <App />
</Provider>
```

When done importing these necessary components, ensure to wrap your <App /> component with the provider and include the store you added recently, this enables your whole app to access the Redux store

### Create a Slice
Of course, Redux- Toolkit introduced slice. A slice is a part of the application’s state that can be updated independently. It contains a set of actions and a reducer that handles those actions. Think of a slice as a certain feature you want to apply different action to it, on different occasions, now each action in the feature (slice) uses the same state, having initial value of  `initialState`. In this app, I have 3 actions running in the same slice. All the actions reside in the reducers object

`src/redux/reducer.js`

```javascript
import { createSlice } from '@reduxjs/toolkit';

const initialState = [];

const todoReducer = createSlice({
  name: 'todos',
  initialState,
  reducers: {};
});

export const reducer = todoReducer.reducer;

```
With this, we can go ahead to add our slice Reducers to the store in `src/redux/store.js`

```javascript
import { configureStore } from '@reduxjs/toolkit';
+ import { reducer } from './reducer';

export const store = configureStore({
+  reducer: reducer,
});

```
This is the basic configuration needed using Redux-toolkit, we are ready to go Redux baby! 
Let’s go about creating actions in `src/redux/reducer.js`

---

#### To Add Note

```javascript
import { createSlice } from '@reduxjs/toolkit';

const initialState = [];

const todoReducer = createSlice({
  name: 'todos',
  initialState,
  reducers: {
+    // Adding new todo
+   addTodo: (state, action) => {
+      return [...state, action.payload];
+    },
  },
});

+ export const { addTodo} = todoReducer.actions;
export const reducer = todoReducer.reducer;

```
The `state` is the current state, with initial value of `initialState`, action.payload is the value passed into the addTodo function in `src/components/TextField/TextField.jsx`
We use our actions to work with the store with the help of the useDispatch hook from react-redux, this is how we **Dispatch** as explained [earlier](#dispatch)

`src/components/TextField/TextField.jsx`

```javascript
import { addTodo } from '../../redux/reducer';
import { useDispatch } from 'react-redux';
const dispatch = useDispatch();

dispatch(
	addTodo({
	id: Math.floor(Math.random() * 100),
	item: text,
})

```
The `addTodo` action takes in the value passed in, which is an object of two key: value pairs and adds it to the array, hence updating the state. Therefore making the state an array of objects with two keys: id and text.

---

#### To Delete Note:

```javascript
import { createSlice } from '@reduxjs/toolkit';

const initialState = [];

const todoReducer = createSlice({
  name: 'todos',
  initialState,
  reducers: {
    // Adding new todo
addTodo: (state, action) => {
     return [...state, action.payload];
   },
+ deleteTodo: (state, action) => {
+      return state.filter((item) => {
+        return item.id !== action.payload;
+      });
+    },
  },
});

+ export const { addTodo, deleteTodo} = todoReducer.actions;
export const reducer = todoReducer.reducer;

```
The `deleteTodo` function checks for a matching id to the one passed in through our dispatch function, to update the state, while removing the matched id from the array
Here, the `action.payload` is `id`
from `src/components/Note/Note.jsx`

```javascript
import { deleteTodo } from '../../redux/reducer';
import { useDispatch } from 'react-redux';
const dispatch = useDispatch();
dispatch(deleteTodo(id));
```
---

#### Update Note:
```javascript
updateTodo: (state, action) => {
      return state.map((todo) => {
      const item = todo.item;
      if (todo.id === action.payload.id) {
         return {
            ...todo,
            [item]: action.payload.text,
          };
        }
        return todo;
      });
    },
```

The `updateTodo` function updates the value of a selected item from the array of objects(different list items), then updates it’s `item` value by the text.

This function takes an object of two key value pairs as seen in `src/components/Note/Note.jsx`

```javascript
import {updateTodo } from '../../redux/reducer';
updateTodo({ id, text: inputRef.current.value });
```

The `id` is a numeric value used to identify an item from the list, the text is a string used to update the text of the identified item.


## Access the state

This is where **selector** comes in, as explained [earlier](#selector) we use it by using the `useSelector` hook from `react-redux`. It helps us extract data from the Redux store state, using a selector function

```javascript
import { useSelector } from 'react-redux';
import Note from '../Note/Note';

function ShowTodo() {
  const list = useSelector((state) => state);
  return (
    <>
      {list &&
        list.map((item) => (
          <Note text={item.item} key={item.id} id={item.id} />
        ))}
    </>
  );
}

export default ShowTodo;
```

And that is how we access data from our store.
Hope you got value!

## Helpful Links
- [Source Code](https://github.com/iampitrus/todo)
- [Live Preview](https://todo-beige-tau.vercel.app/)