skip to Main Content

I am trying to call handleAddNote which is passed from App.js to AddNote.js but I am not able to reference it in AddNote without getting error saying handleAddNote is not a function. I have tried multiple ways but I always get it is not a function or is not defined. In the tutorial I’m following it says to simply call handleAddNote(noteText) in handleSave function but I am not able to.

import Note from './Components/Note';
import NotesList from './Components/NotesList';
import { useState } from 'react';
import { nanoid } from 'nanoid';


const App = () => {

  const[notes, setNotes] = useState([
    {
      id: nanoid(),
      text: "My first note",
      date: "2/12/2024"
    },
    {
      id: nanoid(),
      text: "My second note",
      date: "2/13/2024"
    },
    {
      id: nanoid(),
      text: "My third note",
      date: "2/14/2024"
    },
    {
      id: nanoid(),
      text: "My fourth note",
      date: "2/15/2024"
  }])

  const addNote = (text) => {
        console.log(text);
  }

  return (
    <div className="container">
      <NotesList notes={notes} handleAddNote={addNote}/>
    </div>

  );
}

export default App;
import Note from './Note';
import AddNote from './AddNote';

const NotesList = ({ notes, handleAddNote }) => {
    return (
        <div className="notes-list">
            {notes.map((note)=> 
                <Note id={note.id} text={note.text} date={note.date}/>
            )}

            <AddNote handleAddNote={handleAddNote}/>
        </div>
    );
}

export default NotesList;
import { useState } from 'react';

const AddNote = ({ handleAddNote }) => {
    const [noteText, setNoteText] = useState("");

    const handleChange = (event) => {
        setNoteText(event.target.value);
    };

    const handleSave = () => {
        console.log({handleAddNote});
        {handleAddNote(noteText)};
    };

    return(
        <div className="note new">
            <textarea 
                onChange={handleChange}
                value={noteText}
                className='new-note'
                rows="8" 
                columns="10" 
                placeholder="Type to add a note...">
            </textarea>

            <div className="note-footer">
                <small>200 remaining</small>
                <button className='save' onClick={(noteText)=>handleAddNote(noteText)}>Save</button>
            </div>
        </div>

    );
}

export default AddNote

2

Answers


  1. As of the above code it looks like the function is passed correctly to the child component.

    Remove the curly braces {handleAddNote(noteText)}; from handleSave function just use handleAddNote(noteText);
    and it should work.

    Login or Signup to reply.
  2. I do not see how your project is laid out but made assumptions based on the import statements. We’ll go file by file.

    Before we start, the most important thing is TO ALWAYS have import React from 'react'; at the top of your component files otherwise it’ll lead to problems.

    The directory structure I made looks like so:

    • src
      • Components
        • AddNote.js
        • Note.js (not provided)
        • NotesList.js
      • App.js
      • index.js (runs App.js)

    I do not know what is calling App so I created the file, index.js to handle that.


    TLDR: Here is a demo – https://codesandbox.io/p/sandbox/pseudo-class-sticker-sheet-forked-43k4pg


    Let’s start with:

    index.js

    import { createRoot } from "react-dom/client";
    import App from "./App";
    
    // Clear the existing HTML content
    document.body.innerHTML = '<div id="app"></div>';
    
    // Render your React component instead
    const root = createRoot(document.getElementById("app"));
    root.render(<App />);
    
    

    Pretty self explanatory. Creates the div and renders the App component against it.

    App.js

    import React, { useState } from "react";
    import NotesList from "./Components/NotesList";
    import { nanoid } from "nanoid";
    const App = () => {
      const [notes, setNotes] = useState([
        {
          id: nanoid(),
          text: "My first note",
          date: "2/12/2024",
        },
        {
          id: nanoid(),
          text: "My second note",
          date: "2/13/2024",
        },
        {
          id: nanoid(),
          text: "My third note",
          date: "2/14/2024",
        },
        {
          id: nanoid(),
          text: "My fourth note",
          date: "2/15/2024",
        },
      ]);
    
      const addNote = (text) => {
        const newNote = {
          id: nanoid(),
          text: text,
          date: new Date().toDateString(),
        };
        setNotes([...notes, newNote]);
      };
    
      return (
        <div className="container">
          <NotesList notes={notes} handleAddNote={addNote} />
        </div>
      );
    };
    
    export default App;
    

    I made no changes here outside of adding setNotes so the App renders.

    NotesList.js

    import React from "react";
    import Note from "./Note";
    import AddNote from "./AddNote";
    
    const NotesList = ({ notes, handleAddNote }) => {
      return (
        <div className="notes-list">
          {notes.map((note) => (
            <Note key={note.id} id={note.id} text={note.text} date={note.date} />
          ))}
          <AddNote handleAddNote={handleAddNote} />
        </div>
      );
    };
    
    export default NotesList;
    

    Along with adding import React from 'react' I made sure to use key property so each element in the array is treated separately.

    AddNote.js

    import React, { useState } from "react";
    
    const AddNote = ({ handleAddNote }) => {
      const [noteText, setNoteText] = useState("");
    
      const handleChange = (event) => {
        setNoteText(event.target.value);
      };
    
      const handleSave = () => {
        handleAddNote(noteText);
      };
    
      return (
        <div className="note new">
          <textarea
            onChange={handleChange}
            value={noteText}
            className="new-note"
            rows="8"
            columns="10"
            placeholder="Type to add a note..."
          ></textarea>
    
          <div className="note-footer">
            <small>200 remaining</small>
            <button className="save" onClick={handleSave}>
              Save
            </button>
          </div>
        </div>
      );
    };
    
    export default AddNote;
    
    

    Most changes took place here. I changed the onClick so it points to the handleSave function. Originally, you had:
    onClick={(noteText)=>handleAddNote(noteText)} which is incorrect since nodeText is actually a MouseEvent (onClick = (e: MouseEvent)).

    Hope this clears things up and let me know if you have any issues/concerns.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search