I'm testing the ReactWeather component to make a call to OpenWeatherAPI
I requested an API key and I am using it as stated in the component documentation. This is the code:
import ReactWeather, { useOpenWeather } from 'react-open-weather';
function App() {
const { data, isLoading, errorMessage } = useOpenWeather({
key: 'my api key',
lat: '41.390205',
lon: '2.154007',
lang: 'en',
unit: 'metric', // values are (metric, standard, imperial)
});
return (
<div className="App">
<ReactWeather
isLoading={isLoading}
errorMessage={errorMessage}
data={data}
lang="en"
locationLabel="Barcelona"
unitsLabels={{ temperature: 'C', windSpeed: 'Km/h' }}
showForecast
/>
</div>
);
}
export default App;
When executing the app, the console shows a 401 error:
And the problem is that the endpoint is calling is not correct. The correct endpoint should be /weather and not /onecall
This works:
http://api.openweathermap.org/data/2.5/weather?appid={my api key}&lang=en&units=metric&lat=41.390205&lon=2.154007
So how can I make the function useOpenWeather to call the right endpoint?
Related
Hello Everyone
I'm having a problem within my Typescript code, with my Next.js App.
i cannot find the right type to use with JSX rendering icons, that's fetched from database,
First part of code:
import * as bsIcons from 'react-icons/bs';
import * as faIcons from 'react-icons/fa';
import { GetStaticProps, InferGetStaticPropsType } from 'next';
import { IconType } from 'react-icons/lib';
type option = {
id: number,
opt: string,
url: string,
logo: any,
sub: string[]
}
export const getStaticProps: GetStaticProps<{ options: option[] }> = async () => {
const res = await fetch('http://localhost:3000/api/menu')
const options: option[] = await res.json()
return {
props: {
options
}
}
}
here i had imported the icons libs from react-icons/bs & react-icons/fa then i defined the type of the response option
then i used the Nextjs getStaticProps function to import menu items from the api.
Second part of code:
<ul>
{ options.map(elm => {
let iconList = elm.logo.split('.')[0]
let menuIcon:IconType = elm.logo.split('.')[1]
let Logo: Function;
if(iconList == 'bsIcons'){
Logo = bsIcons[menuIcon]
} else {
Logo = faIcons[menuIcon]
}
return (
<Link key={elm.id} href={`${elm.url}`} style={{ textDecoration: 'none', color: 'powderblue' }}>
<li className={styles.option}>
<Logo style={{padding: '0 .5rem'}}/>
<p>{elm.opt}</p>
</li>
</Link>
)
})}
</ul>
in this part i'm trying to render the fetched data, according to my code, it's working perfectly, but at the VS Code it shows a typescript error at the if statement,
Error:
let menuIcon: IconType
Type 'IconType' cannot be used as an index type.ts(2538)
i don't have any clue of the type i must use at this part, so i imported the IconType from the icons lib it self, but still i cannot fix it.
is there any suggestions for this ?
a Part of fetched data:
{
id: 1,
opt: 'Dashboard',
url: '/dash',
logo: `faIcons.FaGripHorizontal`,
sub: []
},
{
id: 2,
opt: 'Content management',
url: '/content',
logo: `faIcons.FaWarehouse`,
sub: []
},
}
I'm trying to render google map on my react-redux app. Everything was was working fine. Until when I decided to add some custom markers to the rendered google map. Now the page is blank because of this error I see in my browser console
lat_lng.js:21 Uncaught Error: Invalid LatLng object: (37.42216, undefined)
at new e (lat_lng.js:21:1)
at O.convert (lat_lng.js:5:1)
at t.fromLatLngToCenterPixel (index.js:43:1)
I quickly reverted back to the working codes....but it still displays the same error.
These are the relevant codes:
locationPin.js
import { Icon } from '#iconify/react'
import locationIcon from '#iconify/icons-mdi/map-marker'
const LocationPin = ({ text }) => (
<div className="pin">
<Icon icon={locationIcon} className="pin-icon" />
<p className="pin-text">{text}</p>
</div>
)
export default LocationPin;
Map.js
import GoogleMapReact from 'google-map-react'
import LocationPin from './LocationPin';
import { MapContainer } from './style';
const Map = ({ location, zoomLevel }) => {
console.log('location', location);
console.log('zoomLevel', zoomLevel);
return (
<MapContainer>
<GoogleMapReact
bootstrapURLKeys= {{ key: process.env.REACT_APP_API_KEY }}
defaultCenter={location}
defaultZoom={zoomLevel}
>
<LocationPin
lat={location.lat}
long={location.long}
text={location.address}
/>
</GoogleMapReact>
</MapContainer>
)
}
export default Map;
ReservationsDetails.js
import Map from "../../components/map/Map";
import ParkingGridVertical from "../../components/ParkingGridVertical";
import { ParkingGridVerticalWrapper, ReservationsAsideWrapper,
ReservationsDetailsContainer,
ReservationsMainWrapper,
ReservationTypeWrapper,
SearchReservationsWrapper,
SearchResultWrapper,
} from "./style";
const ReservationsDetails = () => {
const reserveParking = [
'https://user-images.githubusercontent.com/51296741/169976664-533d9594-fb24-4e81-b097-ee16fbfe9189.png',
'https://user-images.githubusercontent.com/51296741/169976664-533d9594-fb24-4e81-b097-ee16fbfe9189.png',
'https://user-images.githubusercontent.com/51296741/169976664-533d9594-fb24-4e81-b097-ee16fbfe9189.png',
];
const location = {
address: '1600 Amphitheatre Parkway, Mountain View, california.',
lat: 37.42216,
long: -122.08427,
}
console.log('locationMe', location);
return (
<ReservationsDetailsContainer>
<ReservationsAsideWrapper>
<SearchReservationsWrapper>
<ReservationTypeWrapper>
<p>Single Day</p>
<p>Flex</p>
<p>Monthly</p>
</ReservationTypeWrapper>
<SearchResultWrapper>
<input
type="text"
name="search"
placeholder="Search Address, Place and Event"
/>
<button type="submit">Search</button>
</SearchResultWrapper>
</SearchReservationsWrapper>
<ParkingGridVerticalWrapper>
<ParkingGridVertical
locations={reserveParking}
/>
</ParkingGridVerticalWrapper>
</ReservationsAsideWrapper>
<ReservationsMainWrapper>
<Map location={location} zoomLevel={17} />
</ReservationsMainWrapper>
</ReservationsDetailsContainer>
);
}
export default ReservationsDetails;
Any idea on how to fix this will be appreciated.
All I needed to do was to replace long with lng every where in the above components. And it worked...
Example
long={location.long}
to
lng={location.lng}
My JSX won't show up properly on my React webpage instead I get this output:
<div class='card'>NaNSasha<img src= NaN />Boddy Cane</div>.
The component:
import React, {Component} from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
class App extends Component{
state = {
string : '',
}
componentDidMount(){
let posts = [
{
title: 'somebody toucha my spaghet',
author: 'Karen',
image:'https://media-cdn.tripadvisor.com/media/photo-s/11/69/c7/f9/spagetti.jpg',
location: 'Jimmy John',
description: 'This spagetti is amazing'
},
{
title: `I love food`,
author: 'Sasha',
image:'https://hoodline.imgix.net/uploads/story/image/610603/donuts2.jpg?auto=format',
location: 'Boddy Cane',
description: 'cjndwsijnjcinjw'
}
];
for(let i =0; i < posts.length; i ++){
const header = `<div class='card'>${+posts[i].title}`;
const body = posts[i].author;
const image = `<img src= ${+posts[i].image} />`;
const description = `${posts[i].location}</div>`;
const concatThis = header + body + image + description
this.setState({
string: concatThis
});
};
};
render(){
return(
<div className='container'>
{this.state.string}
</div>
)
}
}
export default App;
P.S I'm a student
This is what you're looking for. The expression +{} is evaluated as NaN. But please use list rendering.
const image = `<img src= ${+posts[i].image} />`;
^ here
It seems that you are trying to build a string which you then store in a state and render that string after it has been updated. This is unfortunately not how you should use React.
The state should only be raw data, like the posts array with objects. It holds the content and data of the component and should not concern itself on other tasks than that. You obviously can put any type of data in a state, like a string.
state = {
title: 'My food blog',
description: 'Awesome stuff about food',
posts: [
{
title: 'somebody toucha my spaghet',
author: 'Karen',
image:'https://media-cdn.tripadvisor.com/media/photo-s/11/69/c7/f9/spagetti.jpg',
location: 'Jimmy John',
description: 'This spagetti is amazing'
},
{
title: `I love food`,
author: 'Sasha',
image:'https://hoodline.imgix.net/uploads/story/image/610603/donuts2.jpg?auto=format',
location: 'Boddy Cane',
description: 'cjndwsijnjcinjw'
}
]
}
The componentDidMount method is triggered whenever the component has been placed on the page and is now working. In there you can do things like making a change to the data or downloading data from the server. It would make sense that you would do that there because then you would first show your component, maybe show it that it is loading and then fetch data from the server. After that is done, update the state of the component with the new data and the render method will be called with the new data. For example (for illustration purposes):
componentDidMount() {
fetch('urlofdatathatyouwant') // Uses AJAX to get data from anywhere you want with the Fetch API.
.then(response => response.json()) // Tells it to read turn the response from JSON into an usable JavaScript values.
.then(data => {
this.setState({
posts: data // Use the new data to replace the posts. This will trigger a new render.
});
});
}
The render method should primarely concern itself with the presentation of the data in your state. In this case it should loop over the elements in the posts state and create a React element for each post.
render() {
const { posts } = this.state;
return(
<div className='container'>
{posts.map(({ title, author, image, location, description }) => (
// Loop over each post and return a card element with the data inserted.
<div className="card">
<span>{title}</span>
<span>{author}</span>
<img src={image} alt={title}/>
<span>{location}</span>
<span>{description}</span>
</div>
))}
</div>
)
}
All put together it would look like this the example below. So the state only holds the data, componentDidMount is a place to do manipulation of your data after the component is on the page and render only outputs the HTML that you need to create with JSX.
import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
class App extends Component{
state = {
posts: [
{
title: 'somebody toucha my spaghet',
author: 'Karen',
image:'https://media-cdn.tripadvisor.com/media/photo-s/11/69/c7/f9/spagetti.jpg',
location: 'Jimmy John',
description: 'This spagetti is amazing'
},
{
title: `I love food`,
author: 'Sasha',
image:'https://hoodline.imgix.net/uploads/story/image/610603/donuts2.jpg?auto=format',
location: 'Boddy Cane',
description: 'cjndwsijnjcinjw'
}
]
}
componentDidMount() {
// Do something here with the posts if you need to.
}
render() {
const { posts } = this.state;
return(
<div className='container'>
{posts.map(({ title, author, image, location, description }, index) => (
<div key={index} className="card">
<span>{title}</span>
<span>{author}</span>
<img src={image} alt={title}/>
<span>{location}</span>
<span>{description}</span>
</div>
))}
</div>
)
}
}
export default App;
You could even make it a bit nicer by making the card element a component as well. And since it does not have any functionality (yet) it only has to control the output.
const Card = ({ title, author, image, location }) => (
<div className="card">
<span>{title}</span>
<span>{author}</span>
<img src={image} alt={title}/>
<span>{location}</span>
<span>{description}</span>
</div>
)
And then import the card into your App component and use it in the render method.
// App.jsx render.
render() {
const { posts } = this.state;
return(
<div className='container'>
{ /* ...post taking all the properties of each post and passes them to the card element */ }
{posts.map((post, index) => <Card key={index} {...post} />)}
</div>
)
}
I'm learning a react course online. When I try to display the list of items from an array using map to display in a child component , I keep getting "cannot read property map of undefined.
Error is thrown while fetching data from users
import React, { Component } from "react";
import ReactDOM from "react-dom";
let userList = [
{ name: "John", age: 24, place: "India" },
{ name: "Henry", age: 24, place: "India" },
{ name: "Ulrich", age: 24, place: "India" }
];
const AppChild = ({ name, age, place, Graduated }) => {
return (
<section>
<p>name: {name}</p>
<p>age: {age}</p>
<p>place: {place}</p>
{/* access the value via props */}
<p>Graduated: {Graduated ? "yes!" : "no!"}</p>
</section>
);
};
export default class App extends Component {
state = {
userExists: true,
isGraduated: true,
loading: true,
};
toggleStatus = () => {
this.setState(prevState => ({
userExists: !prevState.userExists // value : false
}));
};
render() {
const { users } = this.props;
return (
<div>
<h2>Profile</h2>
<h4>
Profile Status is {this.state.userExists ? "Updated" : "Outdated"}
<br />
<button onClick={this.toggleStatus}>Check Status</button>
</h4>
{users.map(user => (
<AppChild
name={user.name}
age={user.age}
place={user.place}
Graduated={this.state.isGraduated} // passing state to child component
/>
))}
</div>
);
}
}
ReactDOM.render(<App users={userList} />, document.getElementById("root"));
To figure out the problem, we follow the bouncing ball. From the error message, I guess that the problem occurs on the line
{users.map(user => (
(You can confirm this from the stack trace given with the error message.)
The error tells you that users is undefined. So we look at the declaration for users:
const { users } = this.props;
Ok, so it is really this.props.users. So we look where this is passed in:
ReactDOM.render(<App users={userList} />, document.getElementById("root"));
Here you are passing the value of userList to a prop named users. However, in the code you show here, there is no variable named userList. This is as far as we can go with the information you have given. You need to find where this variable is declared and initialized to continue solving the problem.
Below is the correct code. In the previous code I was trying to render <App/> in both index.js and App.js. Thanks everyone for helping me out
=>index.js
import React from "react"
import ReactDOM from "react-dom"
import App from "./App"
let userList = [
{ name: "John", age: 24, place: "India" },
{ name: "Henry", age: 24, place: "India" },
{ name: "Ulrich", age: 24, place: "India" }
];
ReactDOM.render(<App users={userList} />, document.getElementById("root"));
=> App.js
import React, { Component } from "react";
// child component
const AppChild = ({ name, age, place, Graduated }) => {
return (
<section>
<p>name: {name}</p>
<p>age: {age}</p>
<p>place: {place}</p>
{/* access the value via props */}
<p>Graduated: {Graduated ? "yes!" : "no!"}</p>
</section>
);
};
// parent component
export default class App extends Component {
state = {
userExists: true,
isGraduated: true,
loading: true,
};
toggleStatus = () => {
this.setState(prevState => ({
userExists: !prevState.userExists // value : false
}));
};
render() {
const { users } = this.props;
return (
<div>
<h2>Profile</h2>
<h4>
Profile Status is {this.state.userExists ? "Updated" : "Outdated"}
<br />
<button onClick={this.toggleStatus}>Check Status</button>
</h4>
{users.map((user) => {
return(
<AppChild
name={user.name}
age={user.age}
place={user.place}
Graduated={this.state.isGraduated} // passing state to child component
/>
)})}
</div>
);
}
}
If you try to log users after following line of code
const { users } = this.props;
you'll see users is undefined.
Error message "cannot read property map of undefined" says the same thing, you can not apply map helper on an undefined variable. The map works with arrays
im trying to display weather icons from open weather map api , but am not entirely sure how to do it , here is the documentation https://openweathermap.org/weather-conditions .. im passing in weather.icon just like its written in the docs but its not working for some reason ,can someone please tell me what i am doing wrong? thanks
app.js
class App extends React.Component {
state = {
temperature: undefined,
city: undefined,
country: undefined,
pressure: undefined,
humidity: undefined,
description: undefined,
rain:undefined,
icon:undefined,
error: undefined
}
handlenum1Change (evt) {
let temp = (evt.target.value);
}
getWeather = async (e) => {
e.preventDefault();
const city = e.target.city.value;
const api_call = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric`);
const data = await api_call.json();
console.log(data)
if (city) {
this.setState({
temperature: data.main.temp,
city: data.name,
icon: data.weather.icon,
rain: data.rain,
pressure: data.main.pressure,
humidity: data.main.humidity,
description: data.weather[0].description,
error: ""
});
} else {
this.setState({
temperature: undefined,
city: undefined,
country: undefined,
humidity: undefined,
description: undefined,
pressure:undefined,
rain : undefined,
error: "Please enter the values."
});
}
}
render() {
return (
<div>
<div className="wrapper">
<div className="main">
<div className="container">
<div className="row">
<div className="col-xs-5 title-container">
</div>
<div className="col-xs-7 form-container">
<form onSubmit={this.getWeather} >
<input type="text" name="city" onChange={this.handlenum1Change} placeholder="City..."/>
<button>Get Weather</button>
</form>
<Weather
temperature={this.state.temperature}
humidity={this.state.humidity}
city={this.state.city}
pressure={this.state.pressure}
description={this.state.description}
rain={this.state.rain}
icon={this.state.icon}
error={this.state.error}
/>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
};
export default App;
weather.js
import React from 'react';
import PropTypes from 'prop-types';
const Weather = props =>
<div>
<p>{props.city}</p>
<p> humidity {props.humidity }</p>
<p> {props.description} </p>
<p> temperature {props.temperature}</p>
<p> atmospheric pressure : {props.pressure}</p>
<p> atmospheric pressure : {props.rain}</p>
<img className="img-fluid" src={props.icon} />
</div>
export default Weather;
In order for you to display the icon, you need to use the URL and not just icon value. Something like this
The value returned from the API is '09d'. So you will have to append the URL with string url to have the weather api url appended with image and image extension.
{http://openweathermap.org/img/w/${props.icon}.png}
Few other things noticed in your code is ,
You are setting default values as undefined, which is not correct.
Please use proper value, something like
state = {
temperature: '',
city: ''
}
https://codesandbox.io/s/6102m4kn3r
as per your code in weather.js
<img src ={`http://openweathermap.org/img/w/${this.props.icon}.png`} alt="wthr img" />
it will display the weather icon...ie
import React, { Component } from 'react';
class Weather extends Component {
render() {
return (
<div>
<p>WeatherNow:
<img src ={`http://openweathermap.org/img/w/${this.props.icon}.png`}
alt="wthr img" />
</p>
</div>
);
}
}
export default Weather;
You have to make change in src attribute of <img>.
As given in Weathermap api you have to request icon by http://openweathermap.org/img/w/10d.png.
Replace 10d.png by props.icon+'.png'. It will work.
In order for you to display the icon, you need to use the URL. Something like the below code
<img src={`http://openweathermap.org/img/w/${data.weather[0].icon}.png`} height="70px" />