DEV Community

Cover image for Building a Simple Note-Taking App with React
Kartik Budhraja
Kartik Budhraja

Posted on

Building a Simple Note-Taking App with React

In this article, we'll delve into the creation of a basic note-taking application using React. By breaking down the code step by step, we'll explore how React components interact to deliver a seamless user experience.

Follow - Linkedin

Features of the Note-Taking Application:

  1. User-Friendly Interface: The application offers an intuitive and aesthetically pleasing user interface, ensuring a seamless experience for users of all backgrounds.

  2. Dynamic Note Creation: Users can create new notes by providing a title and content, enabling them to capture ideas and thoughts quickly.

  3. Effortless Editing: The app allows users to edit existing notes with ease. They can modify the title and content of any note directly from the interface.

  4. Interactive Buttons: Interactive buttons for adding, editing, and deleting notes enhance the user experience. The interface dynamically adjusts based on user actions.

  5. Error Handling with Toast Notifications: The app incorporates toast notifications to handle errors effectively. Users receive timely alerts when they attempt to submit empty notes, guiding them to fill in the necessary fields.

  6. Responsive Design: The application is designed to be responsive, ensuring a seamless experience across various devices, including desktops, tablets, and smartphones.

Setting Up the Project:

Before we dive into the code, make sure you have Node.js and npm (Node Package Manager) installed. If not, you can download and install them from the official Node.js website.

To begin our project, we create a new React application. If you haven't done this before, you can set up a new React project using the following command:

npx create-react-app note-taking-app
cd note-taking-app
Enter fullscreen mode Exit fullscreen mode

Creating the Note-Taking Components:

App.jsx: This is our application's entry point. It imports the NoteApp component and renders it within the div element with the class name App.

import NoteApp from "./NoteApp";

export default function App() {
  return (
    <div className="App">
      <NoteApp />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

NoteApp.jsx: The core functionality resides in this component. It manages the state for notes, handles user input, and maintains the list of notes. This component also contains the logic for adding, updating, deleting, and editing notes.

1. Import Statements and Initial State:

The code begins by importing necessary modules, including styles from "Note.css," React, icons for Add and Edit functionalities, NoteCard component, and components related to toast notifications.
useState hooks are used to create state variables: note to store current note input, values to store an array of notes, and editIndex to track the index of the note being edited.

import "./Note.css";
import React, { useState } from "react";
import AddIcon from "@material-ui/icons/Add";
import NoteCard from "./NoteCard";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import EditIcon from "@material-ui/icons/Edit";

export default function NoteApp() {
  const [note, setNote] = useState({
    title: "",
    content: ""
  });

  const [values, setValues] = useState([]);
  const [editIndex, setEditIndex] = useState(-1);
Enter fullscreen mode Exit fullscreen mode

2. Event Handlers:

handleChange is an event handler that updates the note state when the user types in the input fields (title and content).
handleSubmit handles form submission. If the title or content is empty, it displays an error toast. Otherwise, it either adds a new note to values or updates an existing note if the editIndex is not -1.

const handleChange = (e) => {
  const { name, value } = e.target;
  setNote((prevNote) => {
    return {
      ...prevNote,
      [name]: value
    };
  });
};

const handleSubmit = (e) => {
  e.preventDefault();
  if (!note.title || !note.content) {
    toast.error("Please fill in the field");
    return;
  }

  if (editIndex === -1) {
    setValues((prevValues) => [...prevValues, note]);
  } else {
    // Updating an existing item
    const updatedItems = [...values];
    updatedItems[editIndex] = {
      title: note.title,
      content: note.content
    };
    setValues(updatedItems);
    setEditIndex(-1);
  }

  setNote({
    title: "",
    content: ""
  });
};
Enter fullscreen mode Exit fullscreen mode

3. Delete and Edit Functions:

deleteNote function removes a note from the values array based on its index.
EditNote function sets editIndex and populates the note state with the selected note's data for editing.

const deleteNote = (id) => {
  setValues((prevValues) => prevValues.filter((_, index) => index !== id));
};

const EditNote = (id) => {
  setEditIndex(id);
  setNote({
    title: values[id].title,
    content: values[id].content
  });
};
Enter fullscreen mode Exit fullscreen mode

4. Form and Note Rendering:

The component renders a header with the title "Notes."
A form is displayed where users can input the note title and content. The form also contains a button that toggles between Add and Edit functionality based on the editIndex.
The component maps through the values array and renders individual NoteCard components for each note, passing necessary props.
ToastContainer is used from the react-toastify library for displaying error messages with a timeout of 1000 milliseconds.

return (
    <div className="main">
      <div className="header">
        <h1 className="notes__title">Notes</h1>
      </div>

      <div>
        <form className="create-note" action="">
          <input
            name="title"
            onChange={handleChange}
            value={note.title}
            placeholder="Title"
            type="text"
          />
          <textarea
            name="content"
            onChange={handleChange}
            value={note.content}
            placeholder="Take a note..."
            rows={3}
            type="text"
          />

          <button onClick={handleSubmit}>
            {editIndex === -1 ? <AddIcon /> : <EditIcon />}
          </button>
        </form>
      </div>

      {values &&
        values.map((item, index) => {
          return (
            <NoteCard
              key={index}
              id={index}
              title={item.title}
              content={item.content}
              onDelete={deleteNote}
              onEdit={() => EditNote(index)}
            />
          );
        })}

      <ToastContainer autoClose={1000} />
    </div>
  );
Enter fullscreen mode Exit fullscreen mode

Styling with CSS

body {
  background: #eee;
  background-image: url("https://www.transparenttextures.com/patterns/cubes.png");
  padding: 0 16px;
}
.header {
  display: flex;
  width: 100%;
  justify-content: space-between;
  align-items: center;
  margin: 10px 0px;
}

.notes__title {
  color: rgb(44, 31, 31);
  font-size: 38px;
  font-family: "Montserrat";
  font-weight: 400;
}

.note {
  background: #fff;
  border-radius: 7px;
  box-shadow: 0 2px 5px #ccc;
  padding: 10px;
  width: 240px;
  margin: 16px;
  float: left;
}
.note h1 {
  font-size: 1.1em;
  margin-bottom: 6px;
}
.note p {
  font-size: 1.1em;
  margin-bottom: 10px;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.note button {
  position: relative;
  float: right;
  margin-right: 10px;
  color: rgb(37, 167, 206);
  border: none;
  width: 36px;
  height: 36px;
  cursor: pointer;
  outline: none;
}

form.create-note {
  position: relative;
  width: 480px;
  margin: 30px auto 20px auto;
  background: #fff;
  padding: 15px;
  border-radius: 7px;
  box-shadow: 0 1px 5px rgb(138, 137, 137);
}
form.create-note input,
form.create-note textarea {
  width: 100%;
  border: none;
  padding: 4px;
  outline: none;
  font-size: 1.2em;
  font-family: inherit;
  resize: none;
}
form.create-note textarea {
  margin-top: 5px;
  border-top: 1px solid rgb(196, 190, 190);
}
form.create-note button {
  position: absolute;
  right: 18px;
  bottom: -18px;
  background: rgb(37, 167, 206);
  color: #fff;
  border: none;
  border-radius: 50%;
  width: 36px;
  height: 36px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  cursor: pointer;
  outline: none;
}
Enter fullscreen mode Exit fullscreen mode

Here is the reference of the working code


Conclusion:

In this step-by-step breakdown, we've explored the essential components and functions of a simple note-taking application built with React. Understanding how state management, user input handling, and component interaction work in React can serve as a foundation for more complex applications. By building upon these concepts, developers can create feature-rich, responsive, and interactive web applications. Happy coding!

Follow Me on Social Media!

If you found this article helpful, feel free to connect with me on LinkedIn and Twitter for more programming tips and tutorials. Let's learn and grow together!

LinkedIn: https://www.linkedin.com/in/kartikbudhraja/

Top comments (0)