Necessary Concepts to Build the Notes App in React

Necessary Concepts to Build the Notes App in React

In this module, we will learn the core React concepts that power our Notes App. These concepts include components, state with hooks, event handling, controlled inputs, side effects with useEffect, arrays and mapping, conditional rendering, and external libraries (for drag and drop). Understanding these will show you exactly how the app creates, edits, pins, deletes, reorders, and saves notes.

1) Components

A React component is a reusable function that defines part of the UI and its behavior. In our app, the main component is App.

  • App handles everything: note creation, search, editing, pinning, deleting, drag and drop, as well as export/import.
  • Inside App, we return JSX for the title, input fields, buttons, notes grid, and instructions modal.
  • We didn’t split the app into smaller components, but we could (e.g., a Note component or SearchBar component). This is useful if the app grows larger.

The App component is the “brain” of our project, managing both what the app looks like and how it works.

2) State and Hooks

State in React lets the app “remember” values between renders. When state changes, the UI updates automatically. We used several useState hooks in our app:

const [notes, setNotes] = useState(() => {

const saved = localStorage.getItem("notes");

return saved ? JSON.parse(saved) : [];

});

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

const [search, setSearch] = useState("");

const [editingId, setEditingId] = useState(null);

const [editText, setEditText] = useState("");

const [showInstructions, setShowInstructions] = useState(false);

  • notes stores all notes (with text, color, and pinned status).
  • input is for new note text.
  • search filters notes.
  • editingId and editText handle editing mode.
  • showInstructions toggles the instructions modal.

Whenever we call setters like setNotes or setInput, React re-renders with the updated values.

3) Event Handling

Event handling connects user actions (like clicks or typing) to app behavior.

Examples in our app:

  • Typing a note:

<textarea

value={input}

onChange={(e) => setInput(e.target.value)}

/>

Each keystroke updates input state.

  • Adding a note:

<button onClick={addNote}>Add Note</button>

Clicking runs the addNote function, which creates a new note object and updates state.

  • Deleting a note:

<button onClick={() => deleteNote(note.id)}>❌</button>

This removes the note from the array.

Event handlers make the UI interactive and dynamic.

4) Controlled Inputs

In React, inputs are usually “controlled,” meaning their value is tied to state.

Example:

<input

type="text"

value={search}

onChange={(e) => setSearch(e.target.value)}

/>

  • The value comes from state (search).
  • The onChange updates the state when the user types.

This keeps the UI and state perfectly in sync, which is essential for features like searching and editing.

5) Side Effects with useEffect

The useEffect hook is used when something needs to happen as a side effect of state changes.

In our app, we use it to save notes to localStorage:

useEffect(() => {

localStorage.setItem("notes", JSON.stringify(notes));

}, [notes]);

  • The dependency [notes] means this effect runs every time the notes array changes.
  • This ensures notes are saved in the browser and still available after refreshing the page.

This is what makes our notes persistent.

6) Arrays and Mapping

Arrays allow us to render multiple items dynamically with .map().

Example of rendering notes:

{filteredNotes.map((note, index) => (

<Draggable key={note.id} draggableId={note.id} index={index}>

...

</Draggable>

))}

Here, each note object in the array becomes a draggable note card.

We also use .filter() and .sort() on arrays:

  • .filter() makes the search feature possible.
  • .sort() ensures pinned notes always appear first.

This combination keeps the UI responsive and organized.

7) Conditional Rendering

We only want to show parts of the UI when needed.

Examples:

  • Show the instructions modal only when showInstructions is true:

{showInstructions && (

<div className="modal-backdrop">...</div>

)}

  • Show the edit textarea only when the note is being edited:

{editingId === note.id ? (

<textarea ... />

) : (

<p onDoubleClick={() => startEditing(note.id, note.text)}>{note.text}</p>

)}

Conditional rendering keeps the UI clean and prevents empty or unused elements from appearing.

8) External Libraries (Drag and Drop)

We used the react-beautiful-dnd library to reorder notes by dragging.

Key parts:

  • DragDropContext: Wraps everything draggable and listens for drag events.
  • Droppable: Defines the area where items can be dropped (our notes grid).
  • Draggable: Makes each note draggable.

Example:

<DragDropContext onDragEnd={handleDragEnd}>

<Droppable droppableId="notes" direction="horizontal">

{(provided) => (

<div ref={provided.innerRef} {...provided.droppableProps}>

{filteredNotes.map(...)}

{provided.placeholder}

</div>

)}

</Droppable>

</DragDropContext>

The handleDragEnd function updates the notes array so the new order is saved.

9) File Handling (Export and Import)

We also built export/import for notes using JSON files.

  • Export: Converts notes array to JSON and downloads it as notes.json.
  • Import: Reads a .json file, parses it, and updates state with imported notes.

This feature lets users back up or transfer their notes easily.