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

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:

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

Same code in terms of localStorage worked in React 17, but doesn't work in React 18 [duplicate]

I am creating a react app which is using local storage. I am saving and array of objects to local storage.
when I try to save to local storage the data is saving.
and then when I refresh the page the saved data is becoming empty object,
like this [].
if any one knows why its happening please help me
import React, {useEffect, useState} from 'react';
import Addcontact from './Addcontact';
import './App.css';
import Contactlist from './Contactlist';
import { Header } from './Header';
function App() {
const keyy ="contactlist"
const [contacts, setcontacts] = useState([])
const contactshandler = (contact)=> {
console.log(contact)
setcontacts([...contacts, contact])
}
useEffect(() => {
const getdata = JSON.parse(localStorage.getItem(keyy))
getdata && setcontacts(getdata)
}, [])
useEffect(() => {
localStorage.setItem(keyy, JSON.stringify(contacts));
}, [contacts])
return (
<div className="ui container">
<Header />
<Addcontact contacts={contacts} contactshandler={contactshandler} />
<Contactlist contacts={contacts} />
</div>
);
}
app component
import React, { useState } from 'react'
function Addcontact({contacts, setcontacts, contactshandler}) {
const [user, setuser] = useState({username:'', email:''})
const addvalue = (e) => {
e.preventDefault();
console.log(user)
contactshandler(user)
setuser({username:'', email:''})
}
return (
<div>
<div className='ui main'>
<h2> Add Contact</h2>
<form className='ui form' onSubmit={addvalue}>
<div className=''>
<label>name</label>
<input name="name" placeholder='name' value={user.username} onChange={(e) => setuser({...user, username : e.target.value })} />
</div>
<div className='feild'>
<label>email</label>
<input email='email' placeholder='email' value={user.email} onChange={(e) => setuser({...user, email: e.target.value})} />
</div>
<button>add</button>
</form>
</div>
</div>
)
}
export default Addcontact
export default App;
add component
this is the value showing when saving after refresh this value becomes empty object
enter image description here
console
enter image description here
You don't need useEffect to read the data. You can initially read it.
const [contacts, setcontacts] = useState(JSON.parse(localStorage.getItem(keyy)) ?? [])
and remove
useEffect(() => {
const getdata = JSON.parse(localStorage.getItem(keyy))
getdata && setcontacts(getdata)
}, [])

React Axios fetch response with error Objects are not valid as a React child

Not sure why my api response is not rendering in UI. It does successfully displayed the response in console though.
Error: Objects are not valid as a React child (found: object with keys {result}). If you meant to render a collection of children, use an array instead.
import React from 'react'
import { useState, useEffect } from 'react'
import axios from 'axios'
import * as ReactBootStrap from 'react-bootstrap'
const TextGenerator = () => {
const [usertext, setUsertext] = useState('hello')
let [result, setResult] = useState(null)
let [loading, setLoading] = useState(true)
const handleSubmit = (e) => {
e.preventDefault()
// const text = { usertext }
axios
.get(`http://127.0.0.1:8000/computer programming`)
.then((res) => {
console.log(res)
console.log(res.data)
result = res.data
setResult({ result })
setLoading(false)
})
.catch((error) => console.error(`Error: ${error}`))
}
return (
<div className='text-center .w-75'>
<br />
<form onSubmit={handleSubmit}>
<input
type='text'
required
size='80'
placeholder='Enter text...'
value={usertext}
onChange={(e) => setUsertext(e.target.value)}
/>
<button>Generate Text</button>
</form>
<div>
{loading ? <ReactBootStrap.Spinner animation='grow' /> : { result }}
</div>
</div>
)
}
export default TextGenerator
React sees below object when it tries to render the result in state.
{
result: {
result: <your_data - res.data>
}
}
Try
{loading ? <ReactBootStrap.Spinner animation='grow' /> : result}
instead of
{loading ? <ReactBootStrap.Spinner animation='grow' /> : { result }}
React cannot render object like { result }
And It will still fail since you wrap and save the result as an object.
Change
setResult({ result })
To
setResult(result)
This will still fail if res.data is not a type of string or array of JSX/string Elements.

How to have changeable values in input React JS?

I was trying to set my value in the input value! but after that, I cannot write anything in the input field! I wanted to set values from the back end in value!
We are writing an admin channel to edit the article for that we need already existing article values to edit the article! What am I doing wrong! or Maybe you can suggest a better way to edit the article in the admin channel!
here is the code:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams } from 'react-router';
const EditArticle = (props) => {
const [editValues, setEditValues] = useState([]);
const [changedValues, setChangedValues] = useState('');
console.log('values', editValues);
console.log('changed', changedValues);
const params = useParams();
console.log(params);
const resultsId = params.id;
console.log('string', resultsId);
const [authTokens, setAuthTokens] = useState(
localStorage.getItem('token') || ''
);
const setTokens = (data) => {
localStorage.setItem('token', JSON.stringify(data));
setAuthTokens(data);
// setToken(data['dataValues']['token']);
};
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/article/${resultsId}`
);
setEditValues(res.data);
} catch (err) {}
};
fetchData();
}, [resultsId]);
const inputValue = editValues;
const userToken = props.token;
return (
<div>
<form value={{ authTokens, setAuthTokens: setTokens }}>
<input
value={editValues.title || ''}
onChange={(input) => setChangedValues(input.target.value)}
type='text'
/>
<input
// ref={editValues.shortDesc}
value={editValues.shortDesc}
onChange={(input) => setChangedValues(input.target.value)}
type='text'
/>
<button type='submit'>send</button>
</form>
</div>
);
};
export default EditArticle;
your onChange handler is updating a different state property than what is being used as the value on the input (editValues vs changedValues).
Also you can pass a defaultValue to input that will get used as the default value only.
See more here https://reactjs.org/docs/uncontrolled-components.html
you can use just do it just using editValues. try this:
I just reproduced it without the api call to run the code.
import React, { useState, useEffect } from "react";
const EditArticle = (props) => {
const [editValues, setEditValues] = useState([]);
console.log("values", editValues);
const [authTokens, setAuthTokens] = useState(
localStorage.getItem("token") || ""
);
const setTokens = (data) => {
localStorage.setItem("token", JSON.stringify(data));
setAuthTokens(data);
// setToken(data['dataValues']['token']);
};
useEffect(() => {
const fetchData = async () => {
try {
//here get the data from api and setstate
setEditValues({ title: "title", shortDesc: "shortDesc" });
} catch (err) {}
};
fetchData();
}, []);
return (
<div>
<form value={{ authTokens, setAuthTokens: setTokens }}>
<input
value={editValues.title || ""}
onChange={(input) => setEditValues({title: input.target.value})}
type="text"
/>
<input
value={editValues.shortDesc}
onChange={(input) => setEditValues({shortDesc: input.target.value})}
type="text"
/>
<button type="submit">send</button>
</form>
</div>
);
};
export default EditArticle;

React not importing file. Console shows no errors

Trying to practice api but I'm stuck trying to import the recipe template. The form shows but nothing else. The console also shows no errors. Any help would be appreciated.
Here is the App.js
import React, { useEffect, useState } from "react";
import Recipe from "./Recipe.js";
function App() {
let [recipes, setRecipes] = useState([]);
useEffect(() => {
getRecipes();
}, []);
const getRecipes = async () => {
const response = await fetch(
`///url///`
);
const data = await response.json();
setRecipes = data.hits;
console.log(data.hits);
};
return (
<div className="App">
<form className="search-form">
<input type="text" className="search-bar" />
<button type="submit" className="search-button">
Search
</button>
</form>
{recipes.map(recipe => (
<Recipe />
))}
</div>
);
}
export default App;
Here is Recipe.js
const Recipe = () => {
return (
<div>
<h1>Title</h1>
<p>Calories</p>
</div>
);
};
export default Recipe;
You're not updating the recipes state inside the getRecipes function correctly. You should call the setRecipes state updater function with the new state.
setRecipes = data.hits;
should be
setRecipes(data.hits)

Render page with new data after change Context

I have a form on 'products/add' and I add products to the database, after I submit the request, I redirect to the page where all the products are displayed. However, this page does not display information about the last item I added. How to fix it? How do I render pages after redirects to display the most current data?
'localhost:3333/products/add'
import React, {useState} from 'react';
import api from './api';
import { Redirect } from 'react-router'
const HandleProduct = () => {
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const [redirect, setRedirect] = useState(false);
const updateName = (e) =>{
setName(e.target.value);
}
const updateDescription = (e) =>{
setDescription(e.target.value);
}
const addProduct = (e) =>{
e.preventDefault();
const product = {
name: name,
description: description
}
api.addProduct(product)
.then((req, res) =>{
console.log(res);
setRedirect(true);
})
}
if(redirect) {
return <Redirect to={'/products'} />
}
return (
<div>
<form onSubmit={addProduct}>
<input type="text" name="name" value={name} onChange={updateName}/>
<input type="text" name="description" value={description} onChange={updateDescription}/>
<button>Submit</button>
</form>
</div>
);
}
export default HandleProduct;
List of products(localhost:3333/products):
import React, {useContext} from 'react';
import {ProductsContext} from './ProductsContext';
const ProductsList = () => {
const [data] = useContext(ProductsContext);
return (
<div>
{console.log(data)}
{data.products.map((product, index)=>(
<div key={index}>
<p>{product.name}</p>
<p><i>{product.description}</i></p>
</div>
))}
</div>
);
}
export default ProductsList;

Categories