CRUD using React Redux/Redux-Toolkit for beginners

CRUD using React Redux/Redux-Toolkit for beginners

Today we’ll learn about react-redux and redux toolkit and will make a to-do app using redux-toolkit in a beginner-friendly way

you can read this article on medium

Have a look at what we’re going to build.

No alt text provided for this image

live demo?source code

As we know,?redux?is a globally used state management tool. It prevent props drilling.

Now, what is redux-toolkit ??….?

Redux Toolkit?is officially recommended approach by the redux team for writing Redux logic. It helps to simplify the code. In react-toolkit we can directly mutate the state but inside?It doesn’t actually mutate the state because it uses the Immer library,

Today we’ll make a to-do app using the redux-toolkit??.

So, first and foremost, you must create a react-app.

npx create-react-app todo        

Now let’s add the redux

npm install react-redux        

Add the redux-toolkit

npm install @reduxjs/toolkit        

To generate new id each time install uuid

npm i uuid        

So far we’ve done the installation process ????????

Let’s move to the coding part??

This is the final code and we’ll breakdown it into the simple

import { createSlice } from '@reduxjs/toolkit'
	

	const initialState={
	  todoList:[]
	}
	

	const todoSlice = createSlice({
	  name:'todo',
	  initialState,
	  reducers :{
	    addToDo:(state,action)=>{
	      state.todoList.push(action.payload)
	    },
	    removeToDo:(state,action)=>{
	      state.todoList=state.todoList.filter((todo)=>todo.id!==action.payload);
	    },
	    editToDo:(state,action)=>{
	      state.todoList = state.todoList
	      .map((todo)=>{
	        if(todo.id===action.payload.id){
	          todo.value=action.payload.value
	        }
	        return todo;
	      })
	    }
	  }
	});
	

	export const { addToDo,removeToDo,editToDo } = todoSlice.actions;
	export default todoSlice.reducer;
 ``j        

UI for displaying tasks

import React,{useState} from 'react'
	import { useSelector,useDispatch } from 'react-redux';
	import { addToDo,removeToDo ,editToDo} from './redux/todoSlice';
	import { v4 as uuidv4 } from 'uuid';
	

	const Todo = () => {
	

	  const todoList = useSelector(state=>state.todo.todoList);
	

	  const [taskValue, setTaskValue] = useState('');
	  const dispatch = useDispatch();
	  
	  const handleSubmit = () =>{
	    dispatch(addToDo({id:uuidv4(),value:taskValue}));
	    setTaskValue('')
	  };
	

	  const [editToDoObj,seteditTodoObj] = useState({});
	  const [isEdit,setIsEdit] = useState(false);
	

	  const editHandler = (taskobj) =>{
	    seteditTodoObj(taskobj);
	    setTaskValue(taskobj.value);
	    setIsEdit(true);
	  }
	

	  const saveBtnHandler = () =>{
	    dispatch(editToDo({id:editToDoObj.id,value:taskValue}));
	    setTaskValue('');
	    setIsEdit(false);
	  }
	

	  return (
	    <>
	      <div className='add-todo'>
	        <input 
	          type='text'  
	          placeholder="add todo...."
	          value={taskValue}
	          onChange={(e)=>setTaskValue(e.target.value)}
	        />
	        {
	          isEdit ?
	          <button
	            onClick={()=>saveBtnHandler()}>Save
	          </button>
	          :
	          <button
	            onClick={handleSubmit}>Add
	          </button>
	        }
	      </div>
	      <div className="show-todo">
	        {
	          todoList.map((todo)=>(
	            <div key={todo.id} className="item">
	              <p>{todo.value}</p>
	              <div>
	                <button
	                  className='deletebtn'
	                  onClick={()=>dispatch(removeToDo(todo.id))}
	                >Delete
	                </button>
	                <button
	                  className='editbtn'
	                  onClick={()=>editHandler(todo)}
	                >Edit
	                </button>
	              </div>
	            </div>
	          ))
	        }
	      </div>
	    </>
	  )
	}
	

	export default Todo;;        

First, remove all the unnecessary files that come up with React.

In the?src?folder make a folder redux

No alt text provided for this image

Now let’s focus on our app.

We have to perform three operation

  1. We should be able to add a new task
  2. We should be able to delete the task
  3. We should be able to edit the task

So, let’s begin with the first step i.e. add the new task

First we’ve to import the createSlice method from ‘@reduxjs/toolkit’

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

Let’s understand the createSlice.

createSlice is a function that accepts an initial state, an object of reducer functions, and a “slice name”, and?automatically generates action creators and action types that correspond to the reducers and state.

Let’s initialize the state

const initialState={
 todoList:[]
}        

So our initialState is empty todoList. we don’t have any task.

Now let’s create a todoSlice

	const todoSlice = createSlice({
	  name:'todo',
	  initialState,
	  reducers:{
	  }
	});        

Now let’s add the function to add the task

	const todoSlice = createSlice({
	  name:'todo',
	  initialState,
	  reducers:{
	    addToDo:(state,action)=>{
	      state.todoList.push(action.payload)
	    },
	  }
	});        

We have defined the function?addToDo?that takes two arguments first state and second action(task that we’ll learn soon). This function will update the todoList by pushing the payload.

Let’s also define the two other functions for removing the todo and for editing the todo.

	const todoSlice = createSlice({
	  name:'todo',
	  initialState,
	  reducers:{
	    addToDo:(state,action)=>{
	      state.todoList.push(action.payload)
	    },
	     removeToDo:(state,action)=>{
	      state.todoList=state.todoList.filter((todo)=>todo.id!==action.payload);
	    },
	  }
	});        

This remove function also accepts state and action and filters the task and removes the task whose id matches the action.payload(here action.payload is task.id that we’ll learn soon).

const todoSlice = createSlice({
	  name:'todo',
	  initialState,
	  reducers :{
	    addToDo:(state,action)=>{
	      state.todoList.push(action.payload)
	    },
	    removeToDo:(state,action)=>{
	      state.todoList=state.todoList.filter((todo)=>todo.id!==action.payload);
	    },
	    editToDo:(state,action)=>{
	      state.todoList = state.todoList
	      .map((todo)=>{
	        if(todo.id===action.payload.id){
	          todo.value=action.payload.value
	        }
	        return todo;
	      })
	    }
	  }
	});        

Last function for updating the task. This editToDo function takes two arguments state and action( todo having same id but updating value) after that it maps over the whole todoList and then it matches the passing todo id and replaces the todo value by updating the value whose todo id matches and return the todo.

And let’s export it

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

	const initialState={
	  todoList:[]
	}
	

	const todoSlice = createSlice({
	  name:'todo',
	  initialState,
	  reducers :{
	    addToDo:(state,action)=>{
	      state.todoList.push(action.payload)
	    },
	    removeToDo:(state,action)=>{
	      state.todoList=state.todoList.filter((todo)=>todo.id!==action.payload);
	    },
	    editToDo:(state,action)=>{
	      state.todoList = state.todoList
	      .map((todo)=>{
	        if(todo.id===action.payload.id){
	          todo.value=action.payload.value
	        }
	        return todo;
	      })
	    }
	  }
	});
	

	export const { addToDo,removeToDo,editToDo } = todoSlice.actions;
	export default todoSlice.reducer;        

Here, we're exporting all three functions and reducer obj.

Let’s setup the store

Create a file store in the src folder

No alt text provided for this image

Inside it import configureStore and todoReducer(todoSlice.reducer) form todoSlice.js and create the store and pass the todoReducer inside the reducer obj with a name(here todo). export the store so that it becomes globally accessible.

import { configureStore } from "@reduxjs/toolkit";
	import todoReducer from './redux/todoSlice'
	

	const store = configureStore({
	  reducer:{
	    todo:todoReducer
	  }
	});
	

	export default store;        

Now In index.js import the provider from the react-redux and store from store.js and pass the store

import React from 'react';
	import ReactDOM from 'react-dom/client';
	import App from './App';
	import { Provider } from 'react-redux';
	import store from './store';
	

	const root = ReactDOM.createRoot(document.getElementById('root'));
	root.render(
	  <React.StrictMode>
	    <Provider store={store}>
	      <App />
	    </Provider>
	  </React.StrictMode>
	);        

So now our state is globally accessible.

Let’s create the UI for the tasks

Create another file in src Todo.jsx

No alt text provided for this image
import React from 'react';

	const Todo = () => {
	  return (
	    <div>Todo</div>
	  )
	}
	

	export default 'Todo'        

Now, to get the taskList and perform the actions lets import useSelector, useDispatch from react-redux, import all three function from todoSlice.js and also import the uuid

import { useSelector,useDispatch } from 'react-redux'
import { addToDo,removeToDo ,editToDo} from './redux/todoSlice';
import { v4 as uuidv4 } from 'uuid';;        

useSelector?: Allows you to extract data from the Redux store state, using a selector function.

useDispatch :?it helps to dispatch actions as needed.

const todoList = useSelector(state=>state.todo.todoList);        

**

	import React,{useState} from 'react'
	import { useSelector,useDispatch } from 'react-redux';
	import { addToDo,removeToDo ,editToDo} from './redux/todoSlice';
	import { v4 as uuidv4 } from 'uuid';
	

	const Todo = () => {
	

	  const todoList = useSelector(state=>state.todo.todoList);
	  const dispatch = useDispatch();
	  
	  return (
	    <div>ToDo</div>
	  )
	}
	

	export default Todo;;        

Let’s make the user to add the task

first we have to create the input and submit and also create a state by using useState hook so that we can get the value of input whenever the input value change.

here we have added the onChange hanlder to the input to get the value and set the input value to the taskValue to make it controlled component

import React,{useState} from 'react'
	import { useSelector,useDispatch } from 'react-redux';
	import { addToDo,removeToDo ,editToDo} from './redux/todoSlice';
	import { v4 as uuidv4 } from 'uuid';
	

	const Todo = () => {
	

	  const todoList = useSelector(state=>state.todo.todoList);
	

	  const [taskValue, setTaskValue] = useState('');
	  const dispatch = useDispatch();
	

	  return (
	    <>
	      <div className='add-todo'>
	        <input 
	          type='text'  
	          placeholder="add todo...."
	          value={taskValue}
	          onChange={(e)=>setTaskValue(e.target.value)}
	        />
	          <button
	            onClick={handleSubmit}>Add
	          </button>
	      </div>
	    </>
	  )
	}
	

	export default Todo;;        

let’s define the handleSubmit function to add the task

const handleSubmit = () =>{
dispatch(addToDo({id:uuidv4(),value:taskValue}));
setTaskValue('')
};        

This will dispatch the function addToDo and here we’re passing the action.payload which contains a unique id each time and the taskvalue

No alt text provided for this image

after that we have set the taskValue as an empty string to make the input value empty

No alt text provided for this image
No alt text provided for this image

Let’s display the task by mapping over them

import React,{useState} from 'react'
	import { useSelector,useDispatch } from 'react-redux';
	import { addToDo,removeToDo ,editToDo} from './redux/todoSlice';
	import { v4 as uuidv4 } from 'uuid';
	

	const Todo = () => {
	

	  const todoList = useSelector(state=>state.todo.todoList);
	

	  const [taskValue, setTaskValue] = useState('');
	  const dispatch = useDispatch();
	  
	  const handleSubmit = () =>{
	    dispatch(addToDo({id:uuidv4(),value:taskValue}));
	    setTaskValue('')
	  };
	

	  return (
	    <>
	      <div className='add-todo'>
	        <input 
	          type='text'  
	          placeholder="add todo...."
	          value={taskValue}
	          onChange={(e)=>setTaskValue(e.target.value)}
	        />
	        <button
	            onClick={handleSubmit}>Add
	        </button>
	      </div>
	      <div className="show-todo">
	        {
	          todoList.map((todo)=>(
	            <div key={todo.id} className="item">
	              <p>{todo.value}</p>
	              <div>

	                <button
	                  className='deletebtn'
	                  onClick={()=>dispatch(removeToDo(todo.id))}
	                >Delete
	                </button>

	                <button
	                  className='editbtn'
	                  onClick={()=>editHandler(todo)}
	                >Edit
	                </button>
	              </div>
	            </div>
	          ))
	        }
	      </div>
	    </>
	  )
	}
	

	export default Todo;


;        

Let’s add the delete functionality

As you can see we are dispatching the function?removeToDo?whenever the we click on the delete btn. here we’re passing the todo.id as a payload so that?removeToDo?use this to filter the task

	                <button
	                  className='deletebtn'
	                  onClick={()=>dispatch(removeToDo(todo.id))}
	                >Delete
	                </button>        
No alt text provided for this image

Let’s add the last functionality that is editing the task

Create two another state

No alt text provided for this image

Let’s define the editHandler that takes todo as an argument and set the editToDoObj to the passing todo and set the input value to the passing todo value and also set the edit is true

 const editHandler = (taskobj) =>{
	    setTodoObj(taskobj);
	    setTaskValue(taskobj.value);
	    setIsEdit(true);
	  }        

Let’s also hide the add button when user editing the task instead show the save button

No alt text provided for this image
No alt text provided for this image
  <div className='add-todo'>
	        <input 
	          type='text'  
	          placeholder="add todo...."
	          value={taskValue}
	          onChange={(e)=>setTaskValue(e.target.value)}
	        />
	        {
	          isEdit ?
	          <button
	            onClick={()=>saveBtnHandler()}>Save
	          </button>
	          :
	          <button
	            onClick={handleSubmit}>Add
	          </button>
	        }
	      </div>        

Here we’re checking if isEdit is true that means the user is now editing the task then show the save button else show the add button

Let’s define the saveBtnHandler

const saveBtnHandler = () =>{
	    dispatch(editToDo({id:editToDoObj.id,value:taskValue}));
	    setTaskValue('');
	    setIsEdit(false);
	  }        

It runs when the user clicks on the save button and dispatch the function editTodo and here we’re passing the action.payload that is id which we are extracting from the editToDoObj and passing the updating value.

So that’s all, I hope now you have a good understanding of redux-toolkit and how it works.

Hope you like this.

Happy coding!

want to give suggestions:-

find me on?medium?twitter

have a look at?my portfolio

Email me at [email protected]

要查看或添加评论,请登录

Nidhi Sharma的更多文章

社区洞察

其他会员也浏览了