DEV Community

Cover image for Todo with React,Redux,React Hooks
Amresh Kumar
Amresh Kumar

Posted on

Todo with React,Redux,React Hooks

Let’s get started what functionality we going to add in this step by step:

  1. Adding Task to List
  2. Deleting Task or Multiple
  3. Changing the status of Task
  4. Updating the Task

Let first Create our create app with command:

create-react-app todo
Enter fullscreen mode Exit fullscreen mode

Now Open the todo in code editor, currently Folder structure look like this.

Screen Shot 2021-09-09 at 9.09.44 AM

Open the App.js where we will write our todo's code.

First we create the input with a button where we will try to add the task to the list.
Screen Shot 2021-09-09 at 9.14.19 AM

import React, { useState } from "react";
import "./App.css";

function App() {
  const [input, setInput] = useState("");

  return (
    <div className={container}>
      <form>
        <input className={input} type="text" value={input} onChange={(e) => setInput(e.target.value)} />
        <button className="createbtn btn" type="submit">
          Create
        </button>
      </form>
    </div>
  );
}
export default Todo;

Enter fullscreen mode Exit fullscreen mode

We will go from first line, in the first line we have imported the React, {useState}. here we have imported react library and the useState, which we use to manage the State in functional component.

Now if move to next, first we have created a state for our input const [input, setInput] = useState("");

In the return we have written our JSX for input and button.

For css you can paste this in App.css.

.container {
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.form {
  border: 1px solid;
  padding: 15px;
}

.btn {
  background-color: white;
  color: black;
  font-size: 16px;
  cursor: pointer;
}

.input {
  width: 230px;
  height: 30px;
  border-radius: 5px;
  padding-left: 10px;
  margin-top: 10px;
  margin-bottom: 10px;
}

.createbtn {
  border: 1px solid #fff;
  font-size: 18px;
  color: rgb(255, 60, 0);
  padding: 7px 20px;
  border-radius: 5px;
  margin-left: 25px;
}

.statusbtn {
  border: none;
}

.statusbtn:hover {
  color: red;
}

.deleteContainer {
  position: relative;
}

.deletebtn {
  margin-top: 15px;
  color: red;
  border: 1px solid;
  position: absolute;
  right: 0px;
}

.todotable {
  font-family: Arial, Helvetica, sans-serif;
  border-collapse: collapse;
  min-width: 600px;
  margin-top: 10px;
}

.todotable td,
.todotable th {
  border: 1px solid #ddd;
  padding: 8px;
}

.todotable tr:nth-child(even) {
  background-color: #f2f2f2;
}

.todotable tr:hover {
  background-color: #ddd;
}

.todotable th {
  padding-top: 12px;
  padding-bottom: 12px;
  text-align: left;
  background-color: #434546;
  color: white;
}

.updatebtn {
  border: 1px solid #fff;
  font-size: 18px;
  color: rgb(255, 60, 0);
  padding: 7px 20px;
  border-radius: 5px;
}

.createbtn:hover,
.updatebtn:hover {
  border: 1px solid;
}

Enter fullscreen mode Exit fullscreen mode

Now we will create a Table for showing our Task,
so we will some modification in our App.js.

import React, { useState } from "react";
import "./App.css";

function App() {
  const [input, setInput] = useState("");
  const [selectedItem, setSelectedItem] = useState([]);

  const handleSubmit = () => {
  };

  const handleUpdate = () => {
  };

  const handleCheckbox = () => {
  };

  return (
    <div className="container">
      <form onSubmit={handleSubmit}>
        <input className="input" type="text" value={input} onChange={(e) => setInput(e.target.value)} />
        <button className="createbtn btn" type="submit">
          Create
        </button>
      </form>
      <div>
        <table className="todotable">
          <tbody>
            <tr>
              <th></th>
              <th>My Todo List</th>
              <th>Status</th>
            </tr>
                <tr>
                  <td>
                    <input type="checkbox"/>
                  </td>
                  <td>
                    Title
                  </td>
                  <td>
                    <button className="statusbtn btn">
                      Change State of Task
                    </button>
                  </td>
                </tr>
          </tbody>
        </table>
        <div className="deleteContainer">
          <button className="deletebtn btn">
            Delete items
          </button>
        </div>
      </div>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Now we will move to add redux, for using first we will install the required dependencies.

npm i redux react-redux --save
Enter fullscreen mode Exit fullscreen mode

We will start integrating the redux into our app.
Now we create a folder named redux. Inside of that we will create four files parallely named action.js,reducer.js, store.js,actionTypes. You folder structure will look like this.

Screen Shot 2021-09-09 at 4.41.28 PM

Now we will write code inside store.js

import { createStore } from "redux";
import reducer from "./reducer";

const store = createStore(reducer);

export default store;
Enter fullscreen mode Exit fullscreen mode

Now we will write code inside action.js


import { ADD_TODO, DELETE_TODO, UPDATE_TODO } from "./actionTypes";

export const addTodo = (payload) => {
  return {
    type: ADD_TODO,
    payload: payload,
  };
};

export const updateTodo = (payload) => {
  return {
    type: UPDATE_TODO,
    payload: payload,
  };
};

export const deleteTodo = (payload) => {
  return {
    type: DELETE_TODO,
    payload: payload,
  };
};
Enter fullscreen mode Exit fullscreen mode

Now we will write code inside reducer.js

import { ADD_TODO, DELETE_TODO, UPDATE_TODO } from "./actionTypes";

const initialState = {
  todos: [
    { id: 0, title: "Learn React", completed: true, description: "We need to learn react from basic to advance in 2 months" },
    { id: 1, title: "Learn Redux", completed: false, description: "We need to learn redux after react from basic to advance in 15 days" },
    { id: 2, title: "Build something fun!", completed: false, description: "We need to build a project based on react and redux " },
  ],
};

const returnUpdatedState = (state, action) => {
  return {
    ...state,
    todos: action.payload,
  };
};

function reducer(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO: {
      // Can return just the new todos array - no extra object around it
      console.log(console.log(state));
      return {
        ...state,
        todos: [
          ...state.todos,
          {
            id: state.todos.length,
            title: action.payload,
            desc: "hello",
            completed: false,
          },
        ],
      };
    }
    case DELETE_TODO:
      return returnUpdatedState(state, action);
    case UPDATE_TODO:
      return returnUpdatedState(state, action);

    default:
      return state;
  }
}

export default reducer;
Enter fullscreen mode Exit fullscreen mode

Now we will write code inside actionTypes.js

export const ADD_TODO = "ADD_TODO";
export const UPDATE_TODO = "UPDATE_TODO";
export const DELETE_TODO = "DELETE_TODO";
Enter fullscreen mode Exit fullscreen mode

We need to some modifications in index.js for configuring the redux to react App.

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import store from "./redux/store";

ReactDOM.render(
  <Provider store={store}>
      <App />
  </Provider>,
  document.getElementById("root")
);

Enter fullscreen mode Exit fullscreen mode

Now if we move to the App.js for adding the redux.
it will look something like this.

import React, { useState } from "react";
import { connect } from "react-redux";
import { addTodo, updateTodo, deleteTodo } from "../redux/actions";
import { Link } from "react-router-dom";
import "./App.css";

function App(props) {
  const [input, setInput] = useState("");
  const [selectedItem, setSelectedItem] = useState([]);

  const handleSubmit = (e) => {
    e.preventDefault();
    if (input) {
      props.addTodo(input);
    }
  };

  const handleUpdate = (id) => {
    let getTodo = props.todos.map((e) => {
      if (e.id === id) {
        return { ...e, completed: !e.completed };
      }
      return e;
    });
    props.updateTodo(getTodo);
  };

  const handleCheckbox = (id) => {
    if (!selectedItem.includes(id)) {
      setSelectedItem([...selectedItem, id]);
    } else {
      setSelectedItem(selectedItem.filter((e) => e !== id));
    }
  };
  const handleDelete = () => {
    let updatedTodo = props.todos.filter((e) => !selectedItem.includes(e.id));
    updatedTodo.map((e, index) => ({ ...e, id: index }));
    props.deleteTodo(updatedTodo);
    setSelectedItem([]);
  };
  return (
    <div className="container">
      <form onSubmit={handleSubmit}>
        <input className="input" type="text" value={input} onChange={(e) => setInput(e.target.value)} />
        <button className="createbtn btn" type="submit">
          Create
        </button>
      </form>
      <div>
        <table className="todotable">
          <tbody>
            <tr>
              <th></th>
              <th>My Todos</th>
              <th>Status</th>
            </tr>
            {props.todos.map((e, index) => {
              return (
                <tr key={`${Date.now()} + ${index}`}>
                  <td>
                    <input type="checkbox" defaultChecked={selectedItem.includes(e.id)} onClick={() => handleCheckbox(e.id)} />
                  </td>
                  <td>
                    <Link to={{ pathname: `${e.title}`, state: { ...e } }}>{e.title}</Link>
                  </td>
                  <td>
                    <button className="statusbtn btn" onClick={() => handleUpdate(e.id)}>
                      {e.completed ? "Completed" : "uncomplete"}
                    </button>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        <div className="deleteContainer">
          <button className="deletebtn btn" onClick={handleDelete}>
            Delete {selectedItem.length} items
          </button>
        </div>
      </div>
    </div>
  );
}

const mapStateToProps = (state) => {
  return {
    todos: state.todos,
  };
};

export default connect(mapStateToProps, { addTodo, updateTodo, deleteTodo })(App);
Enter fullscreen mode Exit fullscreen mode

Good Luck for your future, Hope you have learned something new.🚀

Latest comments (0)