DEV Community

Cover image for How to build a Fabulous Todo App using React, Redux and Framer-Motion
CodeBucks
CodeBucks

Posted on • Edited on • Originally published at devdreaming.com

How to build a Fabulous Todo App using React, Redux and Framer-Motion

Hey,

I know building TODO List always won't get you too far😴, But It can teach you basic concepts and implementation of particular framework.

here is the demo of what we're going to build in this tutorial.👇👇
Link: https://react-redux-todo-app-lac.vercel.app/

Now please if you're starting this tutorial watch till the end because doing it half won't teach you anything. So let's dig in.🤩

In this tutorial we're going to build this TODO app with animations using Framer-Motion.

What will you learn after this Tutorial?

  • How to use Redux Toolkit
  • How to use Framer-Motion for awesome animations
  • Method to sort and display lists
  • CRUD operation (obviously🤭)

If you prefer to code along with the same steps while listing to music you can watch this video 👀:

You must have basic understanding of Redux to follow this tutorial, don't worry if you don't know the basics of Redux you can visit my channel, there is playlist to learn redux.

Let's get Started

First, The below is the folder structure for this small project so make sure you create it.

Folder Structure

src
|--redux(folder)
   |--reducer.js (here we will create actions and reducer)
   |--store.js
|--components(folder)
   |--Todos.js
   |--TodoItem.js
    --DisplayTodos.js
|--css(folder)
   |--main.css
Enter fullscreen mode Exit fullscreen mode

Follow below commands to create react-app and install required libraries!

npx create-react-app your-app-name
cd your-app-name
npm install react-redux @reduxjs/toolkit framer-motion react-icons

we're going to use these all four libraries,
react-icons is to add svg files in our app.

First let's add one input and add button in the Todos.js.



As you can see in above code it has one input with handleChange() method and one add button.

Creating Reducer and Store

Now let's create our Reducer and actions.
Open reducer.js file and write below code:

Explanation:

Now here we're going to use createSlice() function.
This function takes 1 object having 3 parameters,
--> name of the slice function
--> initial State
--> All reducer logic inside reducers {} object

Line 1: import createSlice function.

Line 2: create initial state here it is an empty array.

Line 5: Here we have used createSlice function and passed all 3 required parametrs.

Line 13: We have created one action called addTodos this action get an callback function which have two arguments (state, action). Then this function will return state with adding action.payload (payload contains one todo item).

Line 22: Here we have exported addTodos as action from addTodoReducer.

Line 23: Here we have exported reducer from addTodoReducer.

So, let's create our store and pass this reducer.

Open store.js and write below code:

import { configureStore } from "@reduxjs/toolkit";
import { reducer } from "./reducer";

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

export default store;
Enter fullscreen mode Exit fullscreen mode

In the above code we have used configureStore function.

This funcion takes one reducer and automatically takes care for the Redux DevTools extension so we don't have to write about it explicitly.

Now our store is ready with reducer that we have created.

Connecting Redux Store with React App

Let's connect this store to our React application.

I like to connect store in the index.js file.
Open index.js file.

import Provider from the react-redux and store from store.js

import { Provider } from "react-redux";
import store from "./redux/store";
Enter fullscreen mode Exit fullscreen mode

Now just wrap your component with this Provider and pass store in the Provider just like this,

ReactDOM.render(
  <React.StrictMode>
//Just like below 👇
    <Provider store={store}>
      <App />
    </Provider>

  </React.StrictMode>,
  document.getElementById("root")
);
Enter fullscreen mode Exit fullscreen mode

Now our Redux store is connected with our React App.

Connect React component with Redux

Let's use this store and Redux functionalities in the Todos.js component.

To connect this component with Redux we will use connect() method from react-redux.

Open Todos.js file.

import connect method from react-redux.

import { connect } from "react-redux";
Enter fullscreen mode Exit fullscreen mode

Now instead of simple export default Todos change it to this line:

export default connect(null,null)(Todos);
Enter fullscreen mode Exit fullscreen mode

This is how we use connect method, It's like higher order function that takes your component (Todos in our case) and add redux functionalities to it then return it.

Now add props in your component and log this props you will see and Object having dispatch method. Which means your component is now connected with Redux.

Let's use todos state in our component.

To use state from redux we have to pass mapStateToProps method in the connect method.
and to use actions or functions that we created inside the reducer (like addTodos) we have to create and pass mapDispatchToProps method and add it to the coonect method.

So let's create both of this methods in the Todos.js component.

const mapStateToProps = (state) => {
  return {
    todos: state,
  };
};
Enter fullscreen mode Exit fullscreen mode

This method takes state as argument and will return state as we want here i want state as todos.

const mapDispatchToProps = (dispatch) => {
  return {
    addTodo: (obj) => dispatch(addTodos(obj)),
  };
};
Enter fullscreen mode Exit fullscreen mode

This method takes dispatch as argument and it can dispatch action to reducer.
here, I want to add todos so this method returns and addTodo method.
addTodo method dispatch an addTodos action with an obj(which contains todo item, it will acts as action.payload ).

here, make sure to import addTodos action from reducer file.

now add both of this methods in the connect just like this,

export default connect(mapStateToProps, mapDispatchToProps)(Todos);
Enter fullscreen mode Exit fullscreen mode

let's connect input and add button with this state and methods.

Line 23: Here I have created add function. First it will check it todo state is not empty if it is empty then shows an alert else it will use addTodo method from props.
in this method we will pass todo object which contains
id, todo text, completed boolean which is initially false.

Line 50: Make sure to connect add() with onClick of button.

Line 55: here I have mapped values from todos state.
If todos.length > 0 then it will map it and shows all todo items you add.

You can also use Redux DevTools Extension to see actions and state.

Add All operations in the Reducer

Let's add all the required operations in the reducer.

Line 16: removeTodos will filterout items whose id is same as action.payload. (which means while using this action we will pass id as payload)

Line 20: updateTodos is used to change todo text or todo.item. It will check if id is same as passed in action.payload then it will return all other properties of the item and change the text of todos with the passed value.

Line 32: completeTodos will change the completed boolean value of particular item to true.

Line 46: Make sure to export all the required todo actions.

Now we will use all these actions.

Let's separate display todos component from Todos.js file. Remove ul list from it and let's add it in the DisplayTodo item component.

Before creating DisplayTodos.js component, first let's create TodoItem.js component.

so, open TodoItem.js file and write below code.

Don't read this code, First read the explanation.

Now as you saw in the demo each todo item contains 3 buttons edit,completed,delete. and 3 methods connected with these buttons.

Line 2 & 3: This contains import of icons from react-icons library, we will use this icons in edit, update and remove buttons.

Line 7: These are the all required items that we have to pass while displaying TodoItem* component.

  • item --> contains all the data of single todo item
  • updateTodo --> Method to update todo
  • completeTodo --> method to set todo is completed
  • removeTodo --> method to remove todo item

Line 23: Here in the return Inside this li element you can see,

  • textarea --> it shows the todo text as default value.
  • buttons --> after text area there are 3 buttons which contains icons for edit, update and remove, this buttons are connected with all required methods.
  • span --> after these buttons there is one span element which shows done, and it will display only when item.completed is true.

Line 9: It is a ref which is connected with textarea. It's value is true.

Line 30: here, we have used ref value for the disabled attribute, which means while ref is true until then textarea stays disabled.

Line 11: This change Function will enable the textarea and adds focus on it. This function is connected with the edit button.

Line 16: This function is used to update value of the todo item. It will take 3 arguments, id, updated value and event. Then when you press the enter key then it will call the updateTodo method and pass all required things as object and disable the textarea. It is connected on onKeyPress in the textarea at Line 32.

Line 48: This remove button is connected with the remove method. we have to pass id of the item we want to remove in this method.

Now let's use this component inside the DisplayTodos.js file.

open DisplayTodos.js and write below code.

Make sure to import DisplayTodos.js component in the App.js file right after the Todos component.

Line 1-9: Contains all the requried imports.

Line 12 & 18: we have already discussed about both of these method. Both of these methods must be passed in the connect method. One of them is to map state to props while the other method contains all the required methods to dispatch particular actions.

Line 28: This state is for those 3 buttons which are active, completed and all. It is initialised with "active".

Line 31: This div contains all 3 buttons. and onClick of these buttons sort state gets changed based on the button it's values can be "active","completed" or "all".

Line 53: In this ul element we're rendering 3 different lists based on conditions like,

--> Renders active todo items when (item.completed === false) and (sort === "active")

--> Renders completed todo items when (item.completed === true) and (sort === "completed")

--> Renders all todo items when (sort === "all")

Line 61-65: This contains all the data that we need to pass in the TodoItem component.


Now for the Framer-motion and CSS part you can watch the video or read the code from github repository. (It will be more easier to understand when you watch the video then writing here about css and animations )


Full Code of this Tutorial can be found here

✅Useful Resources(Weekly Updates) and Links👉 here

That's the end of this whole Tutorial. 😄

If you're confused about anything related to this topic feel free to ask me 😉!

Also, if you want to learn Basics of Redux then please do visit my channel.

Thanks For Reading and Supporting.😄

my YouTube channel:

@CodeBucks

Follow me on Twitter where I'm sharing lot's of useful resources!

@code.bucks 😉

Top comments (12)

Collapse
 
mb20 profile image
Mb20

@codebucks Thank you so much for this post, I am new to react and redux and I've learned a lot from this "to do list". one question for the reducer functions defined in redux, they all take state and action as parameter, but when we use them in TodoItem, simply just pass the item.id for remove or complete which I understand the id is all we need, but still confused about how these parameter works from action, Thx again.

Collapse
 
codebucks profile image
CodeBucks

Hey, Thanks for appreciation😄
Have you learned the basic Redux without this redux-toolkit. If you haven't then I'd suggest you to try redux without redux-toolkit you'll get the whole idea of how redux works.
here is the article which I have wrote which explains Redux in simple terms,👇
dev.to/codebucks/what-is-redux-sim...

If you have any doubt in this article, reply with specific code or location where you can't understand 😉

Collapse
 
mb20 profile image
Mb20

Thank you for reply, I am confused about reducer.js line 51. I don't see any actions in addTodoReducer object, it is returned by createSlice(), which should be {name:, initialState:, reducers}.

Thread Thread
 
mb20 profile image
Mb20

I checked redux-toolkit.js.org/api/createslice, says createSlice automatically generates the action types and creators that correspond to reducers and state. I think this answered all my questions, in component DisplayTodos, we import addTodos as action creator which will take payload as parameter and return action object. I thought they are reducer functions.

Thread Thread
 
codebucks profile image
CodeBucks

Great that you figured it out yourself🍻, Yes redux-toolkit is a different than simple approach, It will do all the things by itself within createSlice function so we don't have to write more boilerplate code. 😄

Collapse
 
lucianodiisouza profile image
O Primo Dev

I already know a little bit about redux, but i cannot be able to choose between useSelector hook and mapStateToProps, can anyone tell-me the basics difference between it?

Collapse
 
codebucks profile image
CodeBucks

There is nothing you can do with mapStateToProps/mapDispatchToProps that you can't do with the useSelector and useDispatch hooks as well.
I really like answer from this one, You can check it here.
stackoverflow.com/questions/597481...

else there is also an explanation on useSelector in the documentation:
react-redux.js.org/api/hooks

Collapse
 
lucianodiisouza profile image
O Primo Dev

Nice, im happy in know this! I appreciate your attention!

Thread Thread
 
codebucks profile image
CodeBucks

anytime ^_^

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
codebucks profile image
CodeBucks

??

Collapse
 
nibaamine101 profile image
Niba Amine

شكرا