Skip to content

RamziBach/React-Todo-Guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

8 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

React Hooks Todo App

fontawesome react logo

Stylish Todo App. Add todo items to your list and have a productive day.

  • Create
  • Read
  • Update
  • Delete
  • Local Storage
todo gif

Installation

  1. Clone this repo
git clone https://github.com/RamziBach/Todo.git
  1. Install dependencies
npm install
  1. Start development server
npm start

Quick Overview

Creating and Updating onSubmit. Reading and Deleting with array manipulations. Persistence with Local Storage.

Thorough Overview

Let's go through how it's built. Excluding the CSS and the Header.

Dependencies:

  • ReactJS
npx create-react-app my-app
  • uuid
npm i uuid

HTML

<div id="root"></div>

JavaScript

  1. index.js
import React from 'react';
import ReactDOM from 'react-dom';

import App from './components/App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
  1. App.js
import React from 'react';

import Header from './header/Header';
import Todo from './todo/Todo';

import '../style/app.css';

const App = () => {
  return (
    <>
      <Todo />
    </>
  );
};

export default App;
  1. Todo.js

Let's break this one down into bite sized pieces.

  • Imports πŸ‘‡
import React, { useState, useRef, useEffect } from 'react';
import { v4 as uuidv4 } from 'uuid';
  • Write your component πŸ‘‡
import React, { useState, useRef, useEffect } from 'react';
import { v4 as uuidv4 } from 'uuid';

const Todo = () => {
  return null;
};

export default Todo;
  • Write your JSX πŸ‘‡
import React, { useState, useRef, useEffect } from 'react';
import { v4 as uuidv4 } from 'uuid';

const Todo = () => {
  return (
    <div>
      <h1>Todo</h1>
      <form onSubmit={}>
        <input
          ref={}
          onChange={}
          value={}
          maxLength="40"
          placeholder="Enter todo..."
          autocomplete="off"
        />
        <button>Add todo</button>
        <button type="button">Clear</button>
      </form>
      <ul>
        {}
      </ul>
    </div>
  );
};

export default Todo;
  • Add state πŸ‘‡
const [items, setItems] = useState([]); // Empty array
const [text, setText] = useState('');
const [isEditing, setIsEditing] = useState(false);
const [editId, setEditId] = useState('');
import React, { useState, useRef, useEffect } from 'react';
import { v4 as uuidv4 } from 'uuid';

const Todo = () => {
  const [items, setItems] = useState([]);
  const [text, setText] = useState('');
  const [isEditing, setIsEditing] = useState(false);
  const [editId, setEditId] = useState('');

  return (
    <div>
      <h1>Todo</h1>
      <form onSubmit={}>
        <input
          ref={}
          onChange={}
          value={text} // added text state to value
          maxLength="40"
          placeholder="Enter todo..."
          autocomplete="off"
        />
        <button>Add todo</button>
        <button type="button">Clear</button>
      </form>
      <ul>{}</ul>
    </div>
  );
};

export default Todo;
  • Add handle functions πŸ‘‡
const handleChange = e => {};
const handleSubmit = e => {};
const handleClear = () => {};
const handleDelete = id => {};
const handleEdit = (id, text) => {};
const handleIsComplete = (id, text, isComplete) => {};
import React, { useState, useRef, useEffect } from 'react';
import { v4 as uuidv4 } from 'uuid';

const Todo = () => {
  const [items, setItems] = useState([]);
  const [text, setText] = useState('');
  const [isEditing, setIsEditing] = useState(false);
  const [editId, setEditId] = useState('');

  const handleChange = e => {};

  const handleSubmit = e => {};

  const handleClear = () => {};

  const handleDelete = id => {};

  const handleEdit = (id, text) => {};

  const handleIsComplete = (id, text, isComplete) => {};

  return (
    <div>
      <h1>Todo</h1>
      <form onSubmit={handleSubmit}>
        {' '}
        // Added handleSubmit
        <input
          ref={}
          onChange={handleChange} // Added handleChange
          value={text}
          maxLength="40"
          placeholder="Enter todo..."
          autocomplete="off"
        />
        <button>Add todo</button>
        <button
          onClick={handleClear} // Added handleClear
          type="button"
        >
          Clear
        </button>
      </form>
      <ul>{}</ul>
    </div>
  );
};

export default Todo;
  • Write functions πŸ‘‡ (Hard part...)
// Setting state to the input value dynamically on every change
const handleChange = e => setText(e.target.value);
const handleSubmit = e => {
  e.preventDefault(); // Prevent default submit behavior
  if (text.length === 0) return; // Stops submission if nothing is typed in input
  if (isEditing) {
    // Set your state immutably
    // This code will execute when we are editing
    // It will replace our items state with what it had before
    // and make the edit.
    setItems(prevState => {
      const newItems = [...prevState];
      const index = newItems.findIndex(item => item.id === editId);
      newItems.splice(index, 1, { id: uuidv4(), text, isComplete: false });
      return newItems;
    });
    setIsEditing(false);
    setText('');
    setEditId('');
    return; // Leave function after edit
  }
  // Set your state immutably
  // Code here will add new items to state
  setItems(prevState => [
    ...prevState,
    { id: uuidv4(), text, isComplete: false },
  ]);
  setText('');
};
const handleClear = () => {
  if (isEditing) {
    setIsEditing(false);
    setText('');
    setEditId('');
    return;
  }
  setItems([]); // Deletes everything in our state
};
const handleDelete = id => {
  // This returns the previous state but without the index we select.
  setItems(prevState => prevState.filter(item => item.id !== id));
};
const handleEdit = (id, text) => {
  setIsEditing(true);
  setText(text);
  setEditId(id); // This is used in handleSubmit
};
const handleIsComplete = (id, text, isComplete) => {
  if (isComplete) {
    // Immutability
    setItems(prevState => {
      const newItems = [...prevState];
      const index = newItems.findIndex(item => item.id === id);
      newItems.splice(index, 1, { id: uuidv4(), text, isComplete: false });
      return newItems;
    });
    return;
  }
  // Immutability
  setItems(prevState => {
    const newItems = [...prevState];
    const index = newItems.findIndex(item => item.id === id);
    newItems.splice(index, 1, { id: uuidv4(), text, isComplete: true });
    return newItems;
  });
};
  • Add ref underneath your state πŸ‘‡
const inputRef = useRef(null);
<input
  ref={inputRef} // Added ref here
  onChange={handleChange}
  value={text}
  maxLength="40"
  placeholder="Enter todo..."
  autocomplete="off"
/>
  • Add focus to input on Mount πŸ‘‡
useEffect(() => inputRef.current.focus(), []);
  • Finish JSX πŸ‘‡
const mapItems = items.map(item => (
  <li key={item.id}>
    {item.text}
    <button onClick={() => handleDelete(item.id)}>Delete</button>
    <button onClick={() => handleEdit(item.id, item.text)}>Edit</button>
    <button
      onClick={() => handleIsComplete(item.id, item.text, item.isComplete)}
    >
      Complete
    </button>
  </li>
));

return (
  <div>
    <h1>Todo</h1>
    <form onSubmit={handleSubmit}>
      <input
        ref={inputRef}
        onChange={handleChange}
        value={text}
        maxLength="40"
        placeholder="Enter todo..."
        autocomplete="off"
      />
      <button>{isEditing ? 'Update' : `Add #${items.length + 1}`}</button>
      <button onClick={handleClear} type="button">
        {isEditing ? 'Cancel' : 'Clear'}
      </button>
    </form>
    <ul>{mapItems}</ul>
  </div>
);
  • Set local storage πŸ‘‡
useEffect(() => localStorage.setItem('Items', JSON.stringify(items)), [items]);
  • Get local storage πŸ‘‡
const LOCAL_STORAGE = () => JSON.parse(localStorage.getItem('Items')) || [];
const [items, setItems] = useState(LOCAL_STORAGE);

About

React Hooks Todo App Guide

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published