0

I rewrote my code from class-based to function-based. Unfortunately, after rewriting it, I get the error message TypeError: notes.map is not a function.

const App = () => {
  const [id, setId] = useState("");
  const [note, setNote] = useState("");
  const [notes, setNotes] = useState("");

  useEffect(() => {
    getNotes();
    const createNoteListener = API.graphql(
      graphqlOperation(onCreateNote)
    ).subscribe({
      next: noteData => {
        const newNote = noteData.value.data.onCreateNote;
        setNotes(prevNotes => {
          const oldNotes = prevNotes.filter(note => note.id !== newNote.id);
          const updatedNotes = [...oldNotes, newNote];
          return updatedNotes;
        });
        setNote("");
      }
    });
    const deleteNoteListener = API.graphql(
      graphqlOperation(onDeleteNote)
    ).subscribe({
      next: noteData => {
        const deletedNote = noteData.value.data.onDeleteNote;
        setNotes(prevNotes => {
          const updatedNotes = prevNotes.filter(
            note => note.id !== deletedNote.id
          );
          return updatedNotes;
        });
      }
    });
    const updateNoteListener = API.graphql(
      graphqlOperation(onUpdateNote)
    ).subscribe({
      next: noteData => {
        const updatedNote = noteData.value.data.onUpdateNote;
        setNotes(prevNotes => {
          const index = prevNotes.findIndex(note => note.id === updatedNote.id);
          const updatedNotes = [
            ...notes.slice(0, index),
            updatedNote,
            ...notes.slice(index + 1)
          ];
          return updatedNotes;
        });
        setNote("");
        setId("");
      }
    });

    return () => {
      createNoteListener.unsubscribe();
      deleteNoteListener.unsubscribe();
      updateNoteListener.unsubscribe();
    };
  }, []);

  const getNotes = async () => {
    const result = await API.graphql(graphqlOperation(listNotes));
    setNotes(result.data.listNotes.items);
  };

  const handleChangeNote = event => setNote(event.target.value);

  const hasExistingNote = () => {
    if (id) {
      const isNote = notes.findIndex(note => note.id === id) > -1;
      return isNote;
    }
    return false;
  };

  const handleAddNote = async event => {
    event.preventDefault();
    // Check if we have an exisiting note. If so, then update it.
    if (hasExistingNote()) {
      handleUpdateNote();
    } else {
      const input = { note };
      await API.graphql(graphqlOperation(createNote, { input }));
    }
  };

  const handleUpdateNote = async () => {
    const input = { id, note };
    await API.graphql(graphqlOperation(updateNote, { input }));
  };

  const handleDeleteNote = async noteId => {
    const input = { id: noteId };
    await API.graphql(graphqlOperation(deleteNote, { input }));
  };

  const handleSetNote = ({ note, id }) => {
    setNote(note);
    setId(id);
  };

  return (
    <div className="flex flex-column items-center justify-center pa3 bg-washed-red">
      <h1 className="code f2-l">Amplify Notetake</h1>
      {/* Note Form */}
      <form onSubmit={handleAddNote} className="mb3">
        <input
          type="text"
          className="pa2 f4"
          placeholder="Write your note"
          onChange={handleChangeNote}
          value={note}
        />
        <button className="pa2 f4" type="submit">
          {id ? "Update note" : "Add note"}
        </button>
      </form>

      {/* Notes list */}
      <div>
        {notes.map(item => (
          <div key={item.id} className="flex items-center">
            <li onClick={() => handleSetNote(item)} className="list pa1 f3">
              {item.note}
            </li>
            <button
              onClick={() => handleDeleteNote(item.id)}
              className="bg-transparent bn f4"
            >
              <span>&times;</span>
            </button>
          </div>
        ))}
      </div>
    </div>
  );
};

export default withAuthenticator(App, { includeGreetings: true });

3 Answers 3

1

If notes is intended to be an array of notes as it appears to be, you'll want to initialize it with an empty array, so const [notes, setNotes] = useState([]); instead of with an empty string like you currently are.

Sign up to request clarification or add additional context in comments.

6 Comments

There actually still seems to be a problem I now see Line 69:6: React Hook useEffect has a missing dependency: 'notes'. Either include it or remove the dependency array. You can also do a functional update 'setNotes(n => ...)' if you only need 'notes' in the 'setNotes' call react-hooks/exhaustive-deps. After I changed it from "" to []. Do you see any other issue with my code?
At the end of useEffect you have this line: }, []); - you should either add notes to that array, or remove it altogether. If you pass that array in, you need to tell useEffect all state and properties that a change in them will cause the useEffect hook to fire.
Hmm in the course I made about it he said that's necessary so it is only used for the mount and unmount – not on all other effects.
That is what the empty array will do, yes. This is probably not an error and likely a warning? The react docs say there are better ways to do this but that it will work. reactjs.org/docs/…
Ahh, in the very last minute he said he did a mistake and ...notes should be ...prevNotes.
|
0

Array in react hooks should be manipulated like this.

 const [items, setItems] = useState([]);

  const addItem = () => {
    setItems([
      ...items,
      {
        id: items.length,
        value: Math.random() * 100
      }
    ]);
  };

  return (
    <>
      <button onClick={addItem}>Add a number</button>
      <ul>
        {items.map(item => (
          <li key={item.id}>{item.value}</li>
        ))}
      </ul>
    </>
  );

1 Comment

After I changed const [notes, setNotes] = useState([]); to const [notes, setNotes] = useState("");. There actually still seems to be a problem I now see Line 69:6: React Hook useEffect has a missing dependency: 'notes'. Either include it or remove the dependency array. You can also do a functional update 'setNotes(n => ...)' if you only need 'notes' in the 'setNotes' call react-hooks/exhaustive-deps. After I changed it from "" to []. Do you see any other issue with my code?
0

try initializing notes state with []

const [notes, setNotes] = useState([]);

see the following diff

enter image description here

2 Comments

In now see Line 69:6: React Hook useEffect has a missing dependency: 'notes'. Either include it or remove the dependency array. after I changed that. Do you have any other idea why?
this could be a linting warning

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.