Home > front end >  React - Elements not rendering properly
React - Elements not rendering properly

Time:12-21

I'm making a note taking app. I have an array set to state that holds the notes and each note is set to state as an object. My NoteList component maps over the array to render a new Note component when the save button is pressed. Everything works so far, except for the first note. When the first note is saved, the delete button renders but not the user input or date. On every subsequent save, everything renders how it should. I've looked over my code but I'm not sure what is causing this. Can someone please point me in the right direction?

import { useState } from 'react';
import uniqid from 'uniqid';
import NoteList from './components/NoteList';

function App() {
  const [note, setNote] = useState({
    note: '',
    date: '',
    id: ''
  })
  const [notes, setNotes] = useState([])
  const [error, setError] = useState(false);

  function handleAddNote(text) {
    const date = new Date();
    const newNote = {
      text: text,
      date: date.toLocaleDateString(),
      id: uniqid()
    }
    setNote(newNote);
    const newNotes = [
      ...notes,
      note
    ]
    setNotes(newNotes);
  }

  return (
    <div className="App">
      <h1>My Notes</h1>
      <input placeholder='Type to search...'></input>
      <NoteList notes={notes} handleAddNote={handleAddNote}/>
   </div>
  );
}


export default App;

import Note from './Note'
import AddNote from './AddNote'

function NoteList({ notes, handleAddNote }) {
  return (
    <div className='list-container'>
      {notes.map((note) => (
        <Note text={note.text} id={note.id} date={note.date}          
                       key={note.id} notes={notes} note={note}/>
        ))}
        <AddNote handleAddNote={handleAddNote}/>
    </div>
  )
}

export default NoteList;

function Note({ note }) {
  return (
    <div className='note-container'>
      <span className='note-text'>{note.text}</span>
      <div className='note-footer'>
        <p className='note-date'>{note.date}</p>
        <button>Delete</button>
      </div>
    </div>
  )
}

export default Note;


import { useState } from 'react';

function AddNote({ handleAddNote } ) {
  const [noteText, setNoteText] = useState('');

  function handleChange(e) {
    setNoteText(e.target.value);
  }

  function handleSaveNote() {
    if (noteText) {
      handleAddNote(noteText);
      setNoteText('');
    }
  }

  return (
    <div className='new-note-container'>
        <textarea onChange={handleChange} value={noteText} 
          rows='5' cols='30' placeholder='Type to enter a note...'
         </textarea>        
        <div className='count-container'>
            <p>Character Count</p>
            <button onClick={handleSaveNote}>Save</button>
        </div>
      </div>
    )
  }

export default AddNote;

CodePudding user response:

I think that the thing you are missing is that after calling setNote it does not change note on the current render. Only in the next render for that component note will get the new state.

In your case I don't see way you need to have a state for the new note so you can change your App component to be something like this:

function App() {
  const [notes, setNotes] = useState([])
  const [error, setError] = useState(false);

  function handleAddNote(text) {
    const date = new Date();
    const newNote = {
      text: text,
      date: date.toLocaleDateString(),
      id: uniqid()
    }
    setNotes((prevNotes) => [...prevNotes, newNote]);
  }

  return (
    <div className="App">
      <h1>My Notes</h1>
      <input placeholder='Type to search...'></input>
      <NoteList notes={notes} handleAddNote={handleAddNote}/>
   </div>
  );
}

CodePudding user response:

All of these functions, such as adding notes, deleting notes, and searching for notes, are implemented in this code and work properly. I think this might be helpful for you!

import { useState } from "react";
import { uuid } from "uuidv4";

const SelectChip = () => {
  const [notes, setNotes] = useState([]);
  const [searchTerm, setSearchTerm] = useState("");

  function handleAddNote(text) {
    const date = new Date();
    setNotes((prev) => [
      ...prev,
      {
        text: text,
        date: date.toLocaleDateString(),
        id: uuid()
      }
    ]);
  }

  return (
    <div className="App">
      <h1>My Notes</h1>
      <input
        value={searchTerm}
        onChange={(event) => setSearchTerm(event.target.value)}
        placeholder="Type to search..."
      />
      <NoteList
        notes={notes}
        setNotes={setNotes}
        handleAddNote={handleAddNote}
        search={searchTerm}
      />
    </div>
  );
};

export default SelectChip;

function NoteList({ notes, setNotes, handleAddNote, search }) {
  const filteredItems = notes.filter((item) =>
    item.text.toLowerCase().includes(search.toLowerCase())
  );

  return (
    <div className="list-container">
      {filteredItems.map((note) => {
        return (
          <Note
            text={note.text}
            id={note.id}
            date={note.date}
            key={note.id}
            setNotes={setNotes}
            note={note}
          />
        );
      })}
      <AddNote handleAddNote={handleAddNote} />
    </div>
  );
}

function Note({ note, setNotes }) {
  function handleDelete(noteId) {
    setNotes((prev) => prev.filter((note) => note.id !== noteId));
  }

  return (
    <div className="note-container">
      <span className="note-text">{note.text}</span>
      <div className="note-footer">
        <p className="note-date">{note.date}</p>
        <button onClick={() => handleDelete(note.id)}>Delete</button>
      </div>
    </div>
  );
}

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

  function handleChange(e) {
    setNoteText(e.target.value);
  }

  function handleSaveNote() {
    if (noteText) {
      handleAddNote(noteText);
      setNoteText("");
    }
  }

  return (
    <div className="new-note-container">
      <textarea
        onChange={handleChange}
        value={noteText}
        rows="5"
        cols="30"
        placeholder="Type to enter a note..."
      ></textarea>
      <div className="count-container">
        <p>Character Count</p>
        <button onClick={handleSaveNote}>Save</button>
      </div>
    </div>
  );
}
  • Related