Home > OS >  Should I combine two React components to render an element without refreshing?
Should I combine two React components to render an element without refreshing?

Time:10-30

new to React here! I have a web app that allows user create notes and these notes are sent to the database and rendered from there using fetch and useEffect(). When I only had the front-end I could do that with this:

  function addNote(newNote) {
setNotes(prevNotes => {
  return [...prevNotes, newNote];
});
  }

but now that I fetch it from the database I have to refresh the page. Now, I know this can be achieved by getting the database info straight after adding a new object, but I have this separated into two components and I'm not sure how to set it up, I also can't use useEffect doing that. Should I just combine CreateArea and Note? I'm using functional components.

Here's my CreateArea(Note) component:

import React, { useState, useEffect } from "react";
import Header from "./Header";
import Footer from "./Footer";
import Category from "./Category";
import Note from "./Note";
import axios from "axios"

function CreateArea(props) {
const [isExpanded, setExpanded] = useState(false);
const [categories, setCategories] = useState([])
const [notes, setNotes] = useState([])

const [note, setNote] = useState({
title: "",
content: "",
category: ''
  });

function handleChange(event) {
const { name, value } = event.target;
console.log("handleChange called")
setNote(prevNote => {
return {
        ...prevNote,
        [name]: value
      };
    });
  }

function submitNote(e){
      e.preventDefault();
      axios.post("http://localhost:5000/notes/add-note", note)
           .then((res) => {
      setNote({
      category: '',
      title: "",
      content: ""
              })
              

      console.log("Note added successfully");
      console.log(note)
            })
            .catch((err) => {
      console.log("Error couldn't create Note");
      console.log(err.message);
            });

        }


    function expand() {
    setExpanded(true);
      }



      return (
      <div>
          <Header/>
          <Category/>
            <form className="create-note">
      {isExpanded && (
                <input
      name="title"
      onChange={handleChange}
      value={note.title}
      placeholder="Title"
      />
              )}
              <textarea
      name="content"
      onClick={expand}
      onChange={handleChange}
      value={note.content}
      placeholder="Take a note..."
      rows={isExpanded ? 3 : 1}
      />
                <select
                name="category"
      onChange={handleChange}
      value={note.category}>
      {
                      categories.map(function(cat) {
      return <option
      key={cat.category} value={cat.value} > {cat.category} </option>;
                      })
      }
      </select>

              <button onClick={submitNote}>Add</button>
      </form>
      <Note/>
            <Footer/>
      </div>
        );
      }
export default CreateArea;

and my Note component:

import React, {useState,useEffect} from "react";
import axios from "axios";

function Note(props) {
  const [notes, setNotes] = useState([])

  useEffect(() => {
    fetch('http://localhost:5000/notes')
    .then(res => res.json())
  .then(json => {console.log(json)
    setNotes(json)})
  }, [])

  function deleteNote(id) {
    axios.delete(`http://localhost:5000/notes/${id}`)
    .then(() => { console.log("Note successfully deleted")});
  }

return (
  <div>
  {notes.map((noteItem, index) => {
    return (
        <div className="note">
       <h1>{noteItem.title}</h1>
       <p>{noteItem.content}</p>
       <button onClick={() => {deleteNote(noteItem._id)}}>
         Delete
       </button>
       <p>{noteItem.category}</p>
     </div>
  
    );
  })}
  </div>
)
  }
  
  export default Note

I would appreciate it if someone could point me in the right direction!

CodePudding user response:

When using hooks in react you should generally keep them at the top most level in a component structure. I suggest performing your note fetch in the create area and then passing in the notes to your notes component.

Then the second part involves adding new notes. useEffects will run on initial mount and on changes to any listeners created. When you submit a new note, you need to tell the useEffect to run the function attached again. You can do this by adding a [fetch, setFetch] = useState(true) value to your createArea. Have your useEffect listen in on the "fetch" value. Anytime the value of "fetch" is changed, the function attached to the useEffect will be triggered. If the value of "fetch" is true, perform the refetch. Then at the end of the fetch, set the value of "fetch" back to false. Default it to true so it will fetch on initial mount

react - rules of hooks

function CreateArea(props) {
    const [isExpanded, setExpanded] = useState(false);
    const [categories, setCategories] = useState([])
    const [notes, setNotes] = useState([])
    
    const [note, setNote] = useState({
        title: "",
        content: "",
        category: ''
    });

    const [fetch, setFetch] = useState(true);
    useEffect(() => {
        if (fetch) {
            fetch('http://localhost:5000/notes')
            .then(res => res.json())
            .then(json => {
                console.log(json)
                setNotes(json);
                setFetch(false);
            })                
        }
    }, [fetch])

    function submitNote(e) {
        /* ... all of your current code ... */
        setFetch(true); // inside of the .then when you clear the note
    }

    /* ... rest of code ... */

    <Note notes={notes} />

    /* ... rest of code ... */
}
    
  • Related