Data fetch although I'm not clicking the button yet - javascript

right now I'm learning react. I still new about this. So, I make a little code here.
import React, { useState, useEffect } from "react";
import axios from "axios";
const Search = () => {
const [data, setData] = useState({});
const [country, setCountry] = useState("");
const [countryFromButtonClick, setCountryFromButtonClick] = useState();
useEffect(() => {
axios
.get(`https://corona.lmao.ninja/countries/${countryFromButtonClick}`)
.then(res => {
console.log(res.data);
setData(res.data);
})
.catch(err => {
console.log(err);
console.log(err.response.data.message);
});
}, [countryFromButtonClick]);
const HandleChange = e => {
setCountry(e.target.value);
};
const handleClick = () => {
setCountryFromButtonClick(country);
};
return (
<section id="search-country">
<h1> Number of Cases </h1>
<div className="container-fluid">
<div className="input-group mb-3">
<input
type="text"
className="form-control"
placeholder="Search Country..."
value={country}
onChange={HandleChange}
/>
<div className="input-group-append">
<button
className="btn btn-outline-secondary"
type="button"
id="button-addon2"
onClick={handleClick}
>
Search
</button>
</div>
</div>
<h1>
{data.country} {data.cases}
</h1>
</div>
</section>
);
};
export default Search;
The problem is, I'm not clicking the search button yet, but It's already fetch the data.
The console showing error from console.log(err).
Is there anything I can do, So the data only fetch when I click the button?
Thanks.

What's up?
So, when you use useEffect hook and put any variable inside of the array, the code is executed, because of the value changed, so, if you want to fetch this, I recommend to create a function with the code that is inside the useEffect.

Related

Change useState Value everytime I enter Somthing in my Input

This is the code i am working on
So, every time i make change to my input i want state to change which will change my url
but every time that happen it shows an error
Is there a alternative for onKeyPress beacuse it's not working and what change should i do to make that happen
"please read this code and tell me how to console log the JSON of my URL"
import React,{useState} from 'react';
import './App.css';
import axios from 'axios';
import Nav from "./components/Nav.js"
function App() {
const {data,setData} = useState({})
const {city,setCity} = useState('')
const url = `http://api.weatherapi.com/v1/current.json?key=e893692528f845dfad844704220412&q=${city}&aqi=yes`
function searchCity(event){
if(event.key === 'Enter') {
axios.get(url).then((response) => {
setData(response.data)
console.log(response.data)
})
}
}
return (
<div >
<Nav />
<div className='form'>
<input
value={city}
onChange={event => setCity(event.target.value)}
onKeyPress = {searchCity}
placeholder='Enter City'
type="text"
/>
</div>
<div className="Container">
<img src="./Img/top-japan-5.jpg" alt="Japan-as-weatherapp-top" className="main-img"/>
<div className="Temprature">12</div>
<div className="Location">Japan</div>
<div className="Weather">cloudy</div>
<div className="Humidity">Humidity</div>
<div className="line"></div>
<div className="Wind">Wind</div>
</div>
</div>
);
}
export default App;
the error massage
Uncaught TypeError: city is undefined
handleChange App.js:25
React 23
js index.js:5
factory react refresh:6
Webpack 3
useState should use [] not {}
const [data,setData] = useState({})
const [city,setCity] = useState('')
wrap the url around useMemo
const url = useMemo(() => `http://api.weatherapi.com/v1/current.json?key=e893692528f845dfad844704220412&q=${city}&aqi=yes`, [city])
Just off the first glimpse. Your useState is incorrect.
you have
const {data,setData} = useState({})
const {city,setCity} = useState('')
but you need
const [data, setData] = useState({});
const [city, setCity] = useState('');
Also, instead of onKeyPress on the input, I would use onSubmit on a form.
Do this...
import React, { useState } from 'react';
import './App.css';
import axios from 'axios';
import Nav from "./components/Nav.js"
function App() {
const [data, setData] = useState({})
const [city, setCity] = useState('')
function searchCity(event) {
event.preventDefault();
const url = `http://api.weatherapi.com/v1/current.json?key=e893692528f845dfad844704220412&q=${city}&aqi=yes`;
axios.get(url).then((response) => {
setData(response.data)
console.log(response.data)
})
}
return (
<div>
<Nav />
<form onSubmit={searchCity} className='form'>
<input
value={city}
onChange={event => setCity(event.target.value)}
placeholder='Enter City'
type="text"
/>
</form>
<div className="Container">
<img src="./Img/top-japan-5.jpg" alt="Japan-as-weatherapp-top" className="main-img"/>
<div className="Temprature">12</div>
<div className="Location">Japan</div>
<div className="Weather">cloudy</div>
<div className="Humidity">Humidity</div>
<div className="line"></div>
<div className="Wind">Wind</div>
</div>
</div>
);
}
export default App;
I think it would be better to call api in onChange and use event.target.value directly not setting state for it,
something like this :
function searchCity(cityToSearch) {
axios
.get(
`http://api.weatherapi.com/v1/current.json?key=e893692528f845dfad844704220412&q=${cityToSearch}&aqi=yes`
)
.then(response => {
setData(response.data);
console.log(response.data);
});
}
and in input :
<input
value={city}
onChange={event => {
setCity(event.target.value);
if (event.key === 'Enter') {
searchCity(event.target.value);
}
}}
placeholder="Enter City"
type="text"
/>

How to set initial state in useState dependent on another state

There are products coming from API (in the state 'productsList') and I am working on building an input range slider that will have the initial value set to the value of the costly price.
So, all I want is to use this line:
const [maxPriceInSlider, setMaxPriceInSlider] = useState(maxPricedProductPrice);
maxPricedProductPrice comes from the highest value in the productsList state.
but it is not working.
any help is appreciated.
The complete code for the component is:
import React from "react";
import { useEffect, useState } from "react";
import axios from "axios";
import { ColorRing as Loader } from "react-loader-spinner";
import HeroGeneral from "../components/UI/HeroGeneral";
import BidItem from "../components/General/BidItem";
import "./bidslist.css";
const BidsList = () => {
const [loading, setLoading] = useState(false);
const [productsList, setProductsList] = useState([]);
// get maximum priced product price
const maxPricedProductPrice = Math.max(...productsList.map((prod) => prod.basePrice));
const [minPriceInSlider, setMinPriceInSlider] = useState(0);
// --------------------------------------------------------------------------------------
// --------------- I WANT the maxPricedProductPrice to be set as initial state of maxPriceInSlider like this:
// const [maxPriceInSlider, setMaxPriceInSlider] = useState(maxPricedProductPrice);
// But it is not working
// productsList is coming from API
const [maxPriceInSlider, setMaxPriceInSlider] = useState(0);
const onMinPriceSliderChangeHandler = (e) => {
setMinPriceInSlider(e.target.value);
};
const onMaxPriceSliderChangeHandler = (e) => {
setMaxPriceInSlider(e.target.value);
};
// fetch all the prodcuts AFTER 1st page render
useEffect(() => {
// scroll to top on mount
window.scrollTo(0, 0);
setLoading(true);
axios
.get("http://localhost:5000/api/v1/products")
.then((data) => {
setProductsList(data.data.data.products);
setLoading(false);
})
.catch((err) => {
setLoading(false);
});
}, []);
return (
<div>
<HeroGeneral />
<div className="bidlist_page_content">
<aside className="filter">
<h2>Filter by</h2>
<div className="filterby_cat">
<h3>Category: </h3>
<select name="c" id="">
<option value="Electronics">Electronics</option>
<option value="Others">Others</option>
</select>
</div>
<div className="filterby_price">
<h3>
Start price:{" "}
<input
type="range"
name="minPriceInSlider"
value={minPriceInSlider}
min="0"
max={maxPricedProductPrice}
onChange={onMinPriceSliderChangeHandler}
/>
{minPriceInSlider}
</h3>
<h3>
End price:{" "}
<input
type="range"
name="maxPriceInSlider"
value={maxPriceInSlider}
min="0"
max={maxPricedProductPrice}
onChange={onMaxPriceSliderChangeHandler}
/>
{maxPriceInSlider}
</h3>
</div>
</aside>
<div>
<div className="divlist_grid_main">
{loading && (
<Loader
visible={true}
height="100"
width="100"
ariaLabel="blocks-loading"
wrapperStyle={{}}
wrapperClass="blocks-wrapper"
colors={["#212529"]}
/>
)}
{!loading && productsList.length === 0 && "No products found!"}
{productsList.map((prod) => (
<BidItem
key={prod._id}
description={prod.description}
category={prod.category}
name={prod.name}
closesAt={prod.closesAt}
imgURL={prod.imageURL}
prodId={prod._id}
bPrice={prod.basePrice}
/>
))}
</div>
</div>
</div>
</div>
);
};
export default BidsList;
Do you have any trouble with updating the maxPriceInSlider inside the useEffect like the following?
useEffect(() => {
// scroll to top on mount
window.scrollTo(0, 0);
setLoading(true);
axios
.get("http://localhost:5000/api/v1/products")
.then((data) => {
setProductsList(data.data.data.products);
const tempProducts = data.data.data.products;
const maxPricedProductPrice = Math.max(...tempProducts.map((prod) => prod.basePrice));
// update the max price here
setMaxPriceInSlider(maxPricedProductPrice);
setLoading(false);
})
.catch((err) => {
setLoading(false);
});
}, []);
If that doesn't work for you, you can hide the range input until the API call ends and once you have the max price then show that in the screen.
You can try a different approach.
After retrieving data from API and setting productsList also set maxPrieceInSlider at the same time like this:
axios
.get("http://localhost:5000/api/v1/products")
.then((data) => {
const maxPricedProductPrice = Math.max(...productsList.map((prod) => prod.basePrice));
setProductsList(data.data.data.products);
setMaxPriceInSlider(maxPricedProductPrice);
setLoading(false);
})
.catch((err) => {
setLoading(false);
});
this is much more efficient because if you keep getting the max price operation at the beginning of your code like you did, it will hinder your app because each time react re-renders your component, this operation will keep executing again and again needlessly.
let me if it works.

How to solve setState is always one step behind on React JS [duplicate]

This question already has answers here:
Update variable and use it immediately React
(2 answers)
Closed 11 months ago.
I am a beginner. I am learning react js. I am having an problem. setState is always one step behind.
Here is a sample:
Here, when I typed i then the console is showing nothing. Next, when I typed the m it shows i and as it is one step behind.
I have created two functions named handleChange and handleKeyword. The functions are behaving the same. I searched on the internet and got useEffect() suggestion to solve the problem but that has not solved my problem or I can't properly implement it.
Here is my codes:
Home.jsx
import React, { useState, useEffect } from 'react';
import Search from '../../components/searchBar/Search';
import './home.scss';
const Home = () => {
const [search, setSearch] = useState('');
const [keyword, setKeyword] = useState('');
const handleChange = event => {
setSearch(event.target.value);
console.log('Search: ', search);
};
const handleKeyword = () => {
setKeyword(search);
console.log('Keyword:', keyword);
};
return (
<div className="container pb-5">
<Search
handleChange={handleChange}
handleKeyword={handleKeyword}
keyword={keyword}
/>
</div>
);
};
export default Home;
Search.jsx
import React from 'react';
import './search.scss'
const Search = props => {
return (
<div className="d-flex input-group justify-content-center">
<input
type="text"
className="form-control searchBox"
placeholder="Search for copyright free images & videos..."
value={props.value}
onChange={event => props.handleChange(event)}
/>
<button className="btn btn-primary" onClick={() => props.handleKeyword()}>
Search
</button>
</div>
);
};
export default Search;
How can I solve the problem?
In Home.jsx, you can move the console statments inside useEffect with states search and keyword as dependencies to get the updated values. This issue is because react is declarative in nature so it decides when to setState runs. It can even be batched together for performance optimisations. So useEffect can be used in such cases to listen to change in states.
import React, { useState, useEffect } from 'react';
import Search from '../../components/searchBar/Search';
import './home.scss';
const Home = () => {
const [search, setSearch] = useState('');
const [keyword, setKeyword] = useState('');
useEffect(() => {
console.log('Search: ', search);
console.log('Keyword:', keyword);
}, [search, keyword])
const handleChange = event => {
setSearch(event.target.value);
};
const handleKeyword = () => {
setKeyword(search);
};
return (
<div className="container pb-5">
<Search
handleChange={handleChange}
handleKeyword={handleKeyword}
keyword={keyword}
/>
</div>
);
};
export default Home;
The problem is setState just promise you that value will be updated It does not affect your code, just move console.logs outside handleClicks
So, when you set a new state and you will see a new value only after rerender component.
const handleKeyword = () => {
setKeyword(search);
console.log("Keyword:", keyword);
};
console.log("Keyword:2", keyword);
console.log("Keyword:", keyword); will be called in the first render with the old value
console.log("Keyword:2", keyword); will be called in the second render with a new value.
setState is async so changes to the state are not applied immediately.
see here https://reactjs.org/docs/react-component.html#setstate

How can I return text with useState?

I am waiting for the data (when the user submit) i fetch the data then return the Temperature with useState() but i wanted to return a header with it like Temperature:12°C.
Something else is that i wanna round the temperature to 2 decimal places but i don't know how to do so
here is my code:
import axios from 'axios';
import React from 'react'
import {useState, useEffect} from 'react'
import './style.css'
import rain from './use1.png'
function App() {
const [name,setName] = useState('Cairo')
const [res, setRes] = useState(null)
const [pic, setPic] = useState(null)
const [temp, setTemp] = useState('')
const getApi = e => {
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${name}&appid=my_key`)
.then(response=> {
console.log(response.data);
setRes(response.data.name)
setTemp(response.data.main.feels_like-273.15+'°C');
Math.round(temp)
setPic(`https://openweathermap.org/img/w/${response.data.weather[0].icon}.png`)
})}
const handleChange = e => {
setName(e.target.value);
};
return (
<div>
<img className="wallpaper" src={rain}></img>
<div className="content">
<input placeholder="Search.." className="input" onChange={handleChange}></input>
</i>
</div>
<div className="content2">
<h1 className="name">{res}</h1>
<img src={pic}></img>
<h1 className="temp">{temp}</h1>
</div>
</div>
);
}
export default App;
Add a useEffect hook so your component re-renders after your temp state changes.
useEffect(() => {}, [temp]);
In order to round to two decimal places...well, usually I don't like telling people this but that's an extremely easy thing to find out from just using Google or another search engine.
JavaScript math, round to two decimal places
You could do it like:
`Temperature ${(response.data.main.feels_like-273.15).toFixed(2)} °C`
You can do like this
const [temp, setTemp] = useState('')
setTemp(response.data.main.feels_like-273.15+'°C');
return (
<div>
<h1 className="temp"> Temperature {temp?.toFix(2)}</h1>
</div>
)
Could you please provide the full component's code, or at least where is response coming from? Anyway, If the response is being passed from a parent component, then I see no reason to use useState at all.
But if you are fetching the data in the same component, then you need to fetch the data asynchronously:
function component(){
const [temp, setTemp] = useState('Loading temperature...')
useEffect(() => {
fetchTemp().then((response) => {
setTemp(response.data.main.feels_like-273.15+'°C');
})
}, [])
return (
<div>
<h1 className="temp">{temp}</h1>
</div>
)
}
About rounding the number, you can use toFixed(decimals) method.
Example:
let number = 900.1234
console.log(number.toFixed(2))

TypeError: Cannot read properties of undefined (reading 'author')

The error above occurs when I submit a blank form. The API I'm submitting to will throw an error since it should not be left blank. I can't seem to get my head around this. I apologize if this code is poorly-written, but I'm guessing it has to do with one of the pieces of state being undefined when the page is rendered. It seems as if the "catch" block of "handleSubmit" is changing the data state to something undefined.
import "./Homepage.css"
import React, { useState, useEffect, useRef } from "react"
import useFetch from "./useFetch"
import Axios from "axios"
export default function Homepage() {
const [body, setBody] = useState("")
const [sortedData, setSortedData] = useState("")
const [data, setData] = useState("")
const [errorFlash, setErrorFlash] = useState("")
const [successFlash, setSuccessFlash] = useState("")
const posts = useFetch("http://localhost:5000/api/data")
const firstRender = useRef(true)
useEffect(() => {
setData(posts) //initiates data on first render
})
useEffect(() => {
if (firstRender.current) {
firstRender.current = false // Will prevent function from running on first render
return
}
data.sort(function (a, b) {
return new Date(b.date) - new Date(a.date)
})
setSortedData(data)
}, [data]) // Dependency set to "data" state, should run after data is fetched
const handleSubmit = (e) => {
e.preventDefault()
Axios.post("http://localhost:5000/api/react-create-post", { text: body }, { withCredentials: true })
.then((res) => {
console.log(res.data)
setSuccessFlash(res.data.msg) // res.data.msg is "Successfully created post"
setSortedData((prevArray) => [res.data.post, ...prevArray])
setBody("")
})
.catch((err) => {
setErrorFlash("Field cannot be left blank")
})
}
return (
<div>
<center>
<div className="create-container">
<div className="posts-title">Create Post</div>
<form id="theForm" onSubmit={(e) => handleSubmit(e)}>
<textarea onChange={(e) => setBody(e.target.value)} value={`${body}`} id="theInput" className="post-input" name="text" type="text"></textarea>
<button className="submit-btn">POST</button>
</form>
</div>
<div id="postsContainer" className="posts-container">
<div className="posts-title">Latest Posts</div>
{errorFlash ? <div className="error-msg">{errorFlash}</div> : console.log()}
{successFlash ? <div className="success-msg">{successFlash}</div> : console.log()}
<div id="postInput">
{sortedData &&
sortedData.map((item) => {
return (
<div className="post-container" key={item._id}>
<a className="a" href={`/user/${item.author}`}>
<h3 className="author">{item.author}</h3>
</a>
<div className="date">{item.date.toLocaleString()}</div>
<div className="options-cont">
<button id="optionsBtn" className="options-btn">
<i className="fas fa-ellipsis-v"></i>
</button>
<button data-author={`${item.author}`} data-id={`${item._id}`} data-text={`${item.body}`} id="editBtn" className="edit inside-btn invisible">
Edit
</button>
<button data-author={`${item.author}`} data-id={`${item._id}`} id="deleteBtn" className="delete inside-btn invisible">
Delete
</button>
<br></br>
<button className="invisible-two">Delete</button>
</div>
<p className="body-text">{item.body}</p>
</div>
)
})}
</div>
</div>
</center>
</div>
)
}
//useFetch hook in useFetch.js file
import { useState, useEffect } from "react"
export default function useFetch(url) {
const [data, setData] = useState("")
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((info) => {
setData(info)
})
}, [url])
return data
}
///API Code
exports.apiPostCreate = function (req, res) {
let post = new Post(req.body.text, req.verifiedUser.item.username)
post
.create()
.then((item) => {
res.status(201).send({ post: item, msg: "Post successfully created" })
})
.catch((err) => {
res.status(201).send({ err }) //This is what gets sent back in the "catch" block of the client-side
})
}
Basically the error occurs when the "catch" block of "handleSubmit" executes. Everything else seems to work okay.
I figured out the error. In my API after an unsuccessful post attempt I original had this code:
res.status(201).send({ err })
This means that "then" was still executing on the Axios request. I since changed the status code to 500 and now everything works properly.

Categories

Resources