React.js: Component updates only after refreshing the page [Post request]

Viewed 85

Hi guys still new to react, working on a small react app supposed to display pictures of hamsters. Inside of the AddHamster component, I have a Post request that seems to be working fine; " Object are passed into Database! " My issue is that the object only get's displayed after refreshing the page. I need the hamster object to be displayed on the page directly after pressing the Add Button, connected to the form.

Any clue on this?

import React, {useState} from "react";
import HamsterCard from './HamsterCard'
import './AddHamster.css';

const AddHamster = () => {


    const [name, setname ] = useState('')
    const [age, setage ] = useState('')
    const [favFood, setfavFood ] = useState('')
    const [imgName, setImgName ] = useState('')
    const [hamsterItems, setHamsterItems] = useState([])
    
        async function handleAddHamster(){

            const newHamster = {
            name: name,
            age: Number(age),
            favFood: favFood,
            imgName: imgName
           }
           console.log(newHamster, 'newHamster')
   
        const response = await fetch('/hamsters ', {method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify(newHamster) 
        })
        const data = await response.json()
        console.log(data, "this is a data response");
        if (response.status === 200){
            setHamsterItems([...hamsterItems,name, age, favFood, imgName])
            setname('')
            setage('')
            setfavFood('')
            setImgName('') 
        
        }       
    }

  return(
        <div className="add-todo-wrapper">
            <form onSubmit={(e) => e.preventDefault()}>
            <label>name
                <input type="text" 
                name="id"  
                value={name}
                onChange={e => setname(e.target.value)} />
            </label>
                <label>age
                <input type="text" 
                name="id" 
                value={age}
                onChange={e => setage(e.target.value)} />
            </label>
            <label>favFood
                <input type="text" 
                name="id" 
                value={favFood}
                onChange={e => setfavFood(e.target.value)} />
            </label>
            <label>Image
                <input type="text" 
                name="id" 
                value={imgName}
                onChange={e => setImgName(e.target.value)} />
            </label>
            <div className="message">{hamsterItems ? <p>{[...hamsterItems]}</p> : null}</div>
            </form>
            <button onClick={() => handleAddHamster()}>ADD</button>
            <HamsterCard />
        </div>
        
    )

}
export default AddHamster;
import React, {useState, useEffect} from "react";
import './HamsterCard.css';


const HamsterCard = () => {
    const [hamsters, setHamsters] = useState([])

    useEffect(() => {
        async function get(){
        const response = await fetch('/hamsters', {method: 'GET',})
        const data = await response.json() 
        setHamsters(data)
        console.log(data)
     
        } 
       get()    
    }, []  );
    
    return (
        <div className="container"> 
           <div className="hamster-card">
            {hamsters.map((hamster) => (
            <Hamster hamster={hamster}  
            key={hamster.id} />  
            ))
            }
          </div>
         
        </div>    
     
    )
}

export default HamsterCard;
import React, {useState} from "react";
const Hamster = ({name, age, favFood, hamster}) => {
 
   const [hamsterDeleted, setHamsterDeleted] = useState(false)

    async function deleteHamster(id) {
        const response = await fetch(`/hamsters/${id}`, { method: "DELETE" });
        setHamsterDeleted(true)
    
        }
         return (
                hamsterDeleted ? null : (  
                    <div>
                <button onClick={() => deleteHamster(hamster.id)}>Delete</button>
                <h2>{hamster.name}</h2> 
                <p>Ålder:{hamster.age}</p> 
                <p>Favorit mat:{hamster.favFood}</p> 
                <img src={'./img/' + hamster.imgName} alt="hamster"/> 
                </div>
              ))
        }
    
       
    

export default Hamster;

After changing code

setHamsterItems([...hamsterItems,name, age, favFood, imgName])

to

setHamsterItems([...hamsterItems, newHamster])

I get this error message:

enter image description here

2 Answers

In the AddHamster component when you update hamsterItems it renders the whole component but in Hamstercard you are using useEffect to fetch the latest hamsters from the database which runs only the first time the HamsterCard component mounts to re-render the HamsterCard you have to add some dependency in useEffect of HamsterCard so this will re-render the HamesterCard every time you click add button.

for which you can send hamsterItems as props to HamsterCard and pass that to useEffect dependency array.

 <HamsterCard hamsterItems={hamsterItems}/>
function HamsterCard({  hamsterItems }) {
  useEffect(() => {
        async function get(){
        const response = await fetch('/hamsters', {method: 'GET',})
        const data = await response.json() 
        setHamsters(data)
        console.log(data)
     
        } 
       get()    
    }, [hamsterItems]  );

It's now working.. problem that Is was this line:

<div className="message">{hamsterItems ? <p>{[...hamsterItems]}</p> : null}</div>

Was trying to render an object directly into the jsx..

Related