Reputation: 236
All i want is that through App.js, I take input for city name and display the AQI fetched from the API in AirQuality.js. But it just isn't working correctly. Can someone please help me on this? I am new to react API.It works fine if I simply hardcode the city name.
import React from "react";
import "./App.css";
class Airquality extends React.Component {
constructor(props) {
super(props);
this.state = {
info: {},
city: {},
parameters: {},
isLoaded: false,
};
}
getAirquality = (search) => {
fetch(
"https://api.waqi.info/feed/" +
search +
"/?token=3c8f71c8438c1b6a06f60477eaf429fe2b61cd3d",
)
.then((response) => response.json())
.then((data) => {
const newInfo = data.data;
const newCity = newInfo.city;
const tempData = newInfo.iaqi;
const newParameters = tempData.pm25;
const loaded = true;
const newState = Object.assign({}, this.state, {
isLoaded: loaded,
info: newInfo,
city: newCity,
parameters: newParameters,
});
this.setState(newState);
});
};
componentDidMount() {
this.getAirquality(this.props.search);
}
render() {
this.getAirquality(this.props.search);
if (!this.state.isLoaded) {
return <div>....Loading</div>;
} else {
return (
<div className="App">
<h1>
The AQI(Air Quality Index) in{" "}
{this.state.city.name} is {this.state.info.aqi}{" "}
today.
<br />
Concentration of PM2.5 particle :{" "}
{this.state.parameters.v}
</h1>
</div>
);
}
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = { name: "" };
this.handleInput = this.handleInput.bind(this);
}
handleInput(event) {
this.setState({
name: event.target.value,
});
}
render() {
return (
<div className="App">
<form onSubmit={this.handleInput}>
<label>
Enter the city name:
<input
type="text"
onChange={this.handleInput}
/>
</label>
</form>
<Airquality search={this.state.value} />
</div>
);
}
}
Upvotes: 3
Views: 3785
Reputation: 151
Your code has some issues. I'm pasting working code below.
handleInput
and form submit handleFormSubmit
. Using same handler creates confusion and both have different purposes. I recommend using different handlers.<Airquality search={this.state.name} />
value of search props should be this.state.name
.event.preventDefault()
to avoid reloading the page. Refer this stackoverflow answer for more context.this.getAirquality(this.props.search)
inside render and this function is setting the state hence render is being called again which turns into infinite loops. Instead, use componentDidMount
in class components, or useEffect
in function components.import React from "react";
import "./App.css";
class Airquality extends React.Component {
constructor(props) {
super(props);
this.state = {
info: {},
city: {},
parameters: {},
isLoaded: false,
};
}
getAirquality (search) {
fetch(
"https://api.waqi.info/feed/" +
search +
"/?token=3c8f71c8438c1b6a06f60477eaf429fe2b61cd3d",
)
.then((response) => response.json())
.then((data) => {
const newInfo = data.data;
const newCity = newInfo.city;
const tempData = newInfo.iaqi;
const newParameters = tempData.pm25;
const loaded = true;
const newState = Object.assign({}, this.state, {
isLoaded: loaded,
info: newInfo,
city: newCity,
parameters: newParameters,
});
this.setState(newState);
});
};
componentDidMount () {
this.getAirquality(this.props.search);
}
render () {
if (!this.state.isLoaded) {
return <div>....Loading</div>;
} else {
return (
<div className="App">
<h1>
The AQI(Air Quality Index) in{" "}
{this.state.city.name} is {this.state.info.aqi}{" "}
today.
<br />
Concentration of PM2.5 particle :{" "}
{this.state.parameters.v}
</h1>
</div>
);
}
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = { name: "", formSubmit: false };
this.handleInput = this.handleInput.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleInput (event) {
console.log(event.target.value)
this.setState({
name: event.target.value,
});
}
handleFormSubmit (event) {
event.preventDefault()
console.log(this.state.name)
this.setState({formSubmit: true})
}
render () {
return (
<div className="App">
<form onSubmit={this.handleFormSubmit}>
<label>
Enter the city name:
<input
type="text"
onChange={this.handleInput}
/>
</label>
</form>
{this.state.formSubmit && <Airquality search={this.state.name} />}
</div>
);
}
}
Upvotes: 1
Reputation: 169298
You're using search={this.state.value}
where the correct name of the state value is search={this.state.name}
. That's why you always get undefined
in the child component.
Then, some other points:
value={this.state.name}
from the <input>
. This makes your input "semi-controlled" and may lead to weirdness. (The browser console should be warning you about this.)componentDidUpdate
in class components, or useEffect
in function components.Here's how I'd implement this with function components and without external libraries. (With external libraries allowed, I'd use swr
for fetching data without race conditions.
import React from "react";
import "./App.css";
const Airquality = ({ search }) => {
const [isLoaded, setIsLoaded] = React.useState(false);
const [info, setInfo] = React.useState({});
React.useEffect(() => {
setIsLoaded(false);
fetch(
"https://api.waqi.info/feed/" +
search +
"/?token=3c8f71c8438c1b6a06f60477eaf429fe2b61cd3d",
)
.then((response) => response.json())
.then((response) => {
const {data} = response;
const {city, aqi} = data;
setInfo({
city,
pm25: data.iaqi.pm25.v,
aqi,
data,
});
setIsLoaded(true);
});
}, [search]);
if (!isLoaded) {
return <div>....Loading</div>;
}
const {city, pm25, aqi} = info;
return (
<div>
The AQI(Air Quality Index) in {city} is {aqi} today.
<br />
Concentration of PM2.5 particle : {pm25}
</div>
);
};
const App = () => {
const [name, setName] = React.useState("");
return (
<div className="App">
<form onSubmit={this.handleInput}>
<label>
Enter the city name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
</form>
<Airquality search={this.state.value} />
</div>
);
};
Upvotes: 1