visit
Link:
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?
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.
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
npx create-react-app your-app-name
cd your-app-name
npm install react-redux @reduxjs/toolkit framer-motion react-icons
First, let's add one input and add a button in the Todos.js.
import React, { useState } from "react";
const Todos = (props) => {
const [todo, setTodo] = useState("");
const handleChange = (e) => {
setTodo(e.target.value);
};
return (
<div className="addTodos">
<input
type="text"
onChange={(e) => handleChange(e)}
className="todo-input"
value={todo}
/>
<button className="add-btn">
Add
</button>
<br />
</div>
);
};
export default Todos;
Now, let's create our Reducer and actions. Open reducer.js file and write the below code:
import { createSlice } from "@reduxjs/toolkit";
const initialState = [];
const addTodoReducer = createSlice({
name: "todos",
initialState,
reducers: {
//here we will write our reducer
//Adding todos
addTodos: (state, action) => {
state.push(action.payload);
return state;
},
},
});
export const { addTodos } = addTodoReducer.actions;
export const reducer = addTodoReducer.reducer;
Explanation:
Now here we're going to use function.This function takes 1 object having 3 parameters,Line 1: import createSlice function.
Line 2: create initial state here it is an empty array.
Line 3: Here we have used createSlice function and passed all 3 required parameters.
I have created one action called addTodos. This action gets a callback function that has two arguments (state, action). Then, this function will return state with adding action.payload (payload contains one todo item).
Last two lines: Here we have exported addTodos as action from addTodoReducer. and we have exported reducer from addTodoReducer.
So, let's create our store and pass this reducer.Open store.js and write the below code:import { configureStore } from "@reduxjs/toolkit";
import { reducer } from "./reducer";
const store = configureStore({
reducer: reducer,
});
export default store;
Import the Provider from the react-redux and store from store.js.
import { Provider } from "react-redux";
import store from "./redux/store";
Now, just wrap your <App/> 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")
);
Let's use this store and Redux functionalities in the Todos.js component.
To connect this component with Redux we will use method from react-redux.
Open Todos.js file.
Import connect method from react-redux.import { connect } from "react-redux";
export default connect(null,null)(Todos);
Now, add props in your component and log this props you will see and Object having dispatch method. This 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 connect method.
So, let's create both of these methods in the Todos.js component.
const mapStateToProps = (state) => {
return {
todos: state,
};
};
const mapDispatchToProps = (dispatch) => {
return {
addTodo: (obj) => dispatch(addTodos(obj)),
};
};
Here, make sure to import addTodos action from reducer file.Now, add both of these methods in the connect just like this:
export default connect(mapStateToProps,mapDispatchToProps)(Todos);
Line 23: Here I have created add function. First, it will check if the 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 a 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.
Line 16: removeTodos will filterout items whose id is the 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 the 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 the 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 the 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, complete, and delete. and 3 methods connected with these buttons.
Line 2 & 3: This contains the import of icons from the react-icons library, we will use these icons in the edit, update and remove buttons.
Line 7: These are the all required items that we have to pass while displaying TodoItem component.
Line 23: Here in the return Inside this
li
element you can see,Line 9: It is a ref which is connected with
textarea
. Its 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 the 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 the 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 required imports.
Line 12 & 18: we have already discussed both of these methods. 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 )
My YouTube channel:
Follow me on Instagram where I'm sharing lots of useful tools and resources! 😉