Building a Simple Note-Taking App with React
Tags: beginners, learning, react, tutorial
Published: 2023-10-26 19:16:17

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](https://www.linkedin.com/in/kartikbudhraja/)

**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
```

**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>
  );
}
```

**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);
```

**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: ""
  });
};
```

**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
  });
};
```

**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>
  );
```

## 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;
}
```

**Here is the reference of the working code**

{% embed https://codesandbox.io/embed/note-app-reactjs-t8dd85?fontsize=14&hidenavigation=1&theme=dark %}

---

## 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/](https://www.linkedin.com/in/kartikbudhraja/)