Cant access some of the object properties when using openweathermap api - javascript

I am using axios to fetch weather information from openweathermap api in my react application. From the result of the api call (which is a json object), I can access some properties, for example data.base. But cant access data.coord.icon or data.weather[0].id etc.
data = [
coord: { lon: -0.1257,lat: 51.5085},
weather: [{ id: 721,
main: "Haze",
description: "haze",
icon: "50n"
}],
base: "stations"
]
I tried all the possible combinations. When trying to return data.coord, got the error Objects are not valid as a React child (found: object with keys {lon, lat}). If you meant to render a collection of children, use an array instead
But data.coord.lon gives lon of undefined
import React, { Component } from 'react';
import axios from 'axios';
export class WeatherInfo extends Component {
constructor(props) {
super(props)
this.state = {
isFetching: false,
data: [],
}
}
//function to fetch weather information
async getWeatherData(lat, lon) {
const weatherApi = `http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${process.env.REACT_APP_WEATHER_KEY}`
try {
this.setState({ ...this.state, isFetching: true });
const response = await axios.get(weatherApi);
this.setState({ data: response.data, isFetching: false });
console.log(response.data)
} catch (error) {
console.log(error);
this.setState({ isFetching: false })
}
}
//function to get access to users location and to call getWeatherData function
weatherInit = () => {
const success = (position) => {
this.getWeatherData(position.coords.latitude, position.coords.longitude);
}
const error = () => {
alert('Unable to retrieve location.');
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success, error);
} else {
alert('Your browser does not support location tracking, or permission is denied.');
}
}
componentDidMount() {
this.weatherInit();
}
render() {
const { data } = this.state;
return (
<div>
<p>{data.name}</p>
</div>
)
}
}
export default WeatherInfo

Here is the example of how you can display various data returned by the API.
import React, {
Component
} from 'react';
import axios from 'axios';
export class WeatherInfo extends Component {
constructor(props) {
super(props)
this.state = {
isFetching: false,
data: [],
}
}
//function to fetch weather information
async getWeatherData(lat, lon) {
const weatherApi = `http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${process.env.REACT_APP_WEATHER_KEY}`
try {
this.setState({ ...this.state,
isFetching: true
});
const response = await axios.get(weatherApi);
if(response.status===200){
//update state only if status is 200
this.setState({
data: response.data,
isFetching: false
});
console.log(response.data)
}
} catch (error) {
console.log(error);
this.setState({
isFetching: false
})
}
}
//function to get access to users location and to call getWeatherData function
weatherInit = () => {
const success = (position) => {
this.getWeatherData(position.coords.latitude, position.coords.longitude);
}
const error = () => {
alert('Unable to retrieve location.');
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success, error);
} else {
alert('Your browser does not support location tracking, or permission is denied.');
}
}
componentDidMount() {
this.weatherInit();
}
render() {
const {data} = this.state;
if (data) {
return (
<div >
//display coord
<p > {data.coord.lon} < /p>
<p > {data.coord.lat} < /p>
// display weather ids
{data.weather.map(item => {
return (
< p > { item.id } < /p>) })
}
< p > { data.name } < /p> < / div >
)
}
else {
return (<div>Data is loading or Not Found</div>)}
}
}
}
export default WeatherInfo
Necessarily you need to create an JSX element for each value you want to display.
Sorry, for formatting.

Related

How to set JSON array to state in React?

I have this bellow App.js code:
import React, { Component } from 'react';
import axios from 'axios'
class Axios extends Component {
constructor() {
super();
this.state = {
item : '',
}
}
componentDidMount() {
axios.get('https://restcountries.com/v3.1/capital/lima')
.then( response => {
const data = response.data.map(( data )=>{
this.setState({
item : data
});
});
})
.catch( error => {
alert( error );
});
}
prepare() {
console.log( this.state.item );
}
render() {
return (
<div>{this.prepare()}</div>
)
}
}
export default Axios;
My goal is to get the common name from this API: https://restcountries.com/v3.1/capital/lima
Now on componentDidMount() method, I need to set the API return data to the item state so that I can loop through using the prepare method.
But I don't have any idea how to set the API return array JSON data to the item state?
Update your state.item to a blank array.
constructor() {
super();
this.state = {
item : [],
}
}
In componentDidMount(), update the code to accept response :
componentDidMount() {
axios.get('https://restcountries.com/v3.1/capital/lima')
.then( response => {
this.setState({
item : response.data
});
})
.catch( error => {
alert( error );
});
}
In render(), you can use map on state.item and can loop on it.
render() {
return (
<div>{this.state.item.map(data,index)=>(
//some UI mapping to each `data` in `item` array
)}</div>
)
}
You just have to do assing response.data to item as:
Live Demo
componentDidMount() {
axios
.get("https://restcountries.com/v3.1/capital/lima")
.then((response) => {
this.setState({
item: response.data
})
})
.catch((error) => {
alert(error);
});
}
You should check this out.
import React, { Component } from "react";
import axios from "axios";
class Axios extends Component {
constructor() {
super();
this.state = {
item: []
};
}
componentDidMount() {
axios
.get("https://restcountries.com/v3.1/capital/lima")
.then((response) => {
this.setState({
item: response && response.data
});
})
.catch((error) => {
alert(error);
});
}
prepare() {
return <div>{console.log("Item", this.state.item)}</div>;
}
render() {
return <div>{this.prepare()}</div>;
}
}
export default Axios;

React component fails on react-pull-to-refresh

I have a fairly simple ASP.NET site with a react front-end. It has a component MetaWeatherForecast that fetches some data from an API endpoint and displays it in a table. That works fine.
After pulling in react-pull-to-refresh into the project and attaching it to the component, the table initially loads and fetches the data on the first load, but then fails as soon as I pull the table to refresh.
Here's a trimmed version of the component in its current form:
MetaWeatherForecast.js
import React, { Component } from 'react';
import authService from './api-authorization/AuthorizeService'
import Moment from 'moment';
import ReactPullToRefresh from 'react-pull-to-refresh'
export class MetaWeatherForecast extends Component {
static displayName = MetaWeatherForecast.name;
constructor(props) {
super(props);
this.state = {
locationForecast: {}, loading: true, success: true, errorMessage: null };
}
componentDidMount() {
this.populateWeatherData();
}
static renderForecastsTable(locationForecast) {
// html markup for the table
}
static renderError(errorMessage) {
// error markup
}
handleRefresh(resolve, reject) {
let success = this.populateWeatherData();
if (success)
resolve();
else
reject();
}
async populateWeatherData() {
this.setState({ locationForecast: {}, loading: true, success: true, errorMessage: null});
const token = await authService.getAccessToken();
const response = await fetch('api/metaweatherforecast/GetFiveDayForecast/44544', {
headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
});
const baseResponse = await response.json();
console.log(baseResponse);
this.setState({ locationForecast: baseResponse.data, loading: false, success: baseResponse.success, errorMessage: baseResponse.errorMessage });
return baseResponse.success;
}
getContent() {
let contents;
if (this.state.loading) {
contents = <p><em>Fetching forecast...</em></p>
} else {
contents = this.state.success
? MetaWeatherForecast.renderForecastsTable(this.state.locationForecast)
: MetaWeatherForecast.renderError(this.state.errorMessage);
}
return contents;
}
render() {
return (
<ReactPullToRefresh
onRefresh={this.handleRefresh}
style={{
textAlign: 'center'
}}>
<div>
<p><em>Pull down to refresh</em></p>
<h1 id="tabelLabel" >Meta Weather forecast</h1>
{this.getContent()}
</div>
</ReactPullToRefresh>
);
}
};
The error being thrown after pulling the table is as follows and is thrown inside the handleRefresh() method:
Uncaught (in promise) TypeError: this.populateWeatherData is not a function
Any ideas or suggestions would be most welcome
In react classes, you have to bind this in the constructor
constructor(props) {
...
this.<method> = this.<method>.bind(this);
}
I like using this library.

handleScroll value inside React Component

I retrieve data from a paginated API. I would therefore like to set up a system that fetch the data of a new page as soon as the user scrolls 70% of his web page.
Do you have an elegant solution for doing this in React ?
Here is my component:
import React, { Component } from 'react';
import Card from './Card';
class Main extends Component {
constructor(props) {
super(props);
this.url = 'https://rickandmortyapi.com/api/character';
this.handleScroll = this.handleScroll.bind(this);
this.state = {
data: [],
canLoad: true,
};
}
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
this.fetchData();
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
};
handleScroll(event) {
// get scrollY value here and call fetchData() if scroll value > 70% of height page
};
async fetchData() {
try {
const res = await fetch(this.url);
const data = await res.json();
this.setState({ data: [...this.state.data, ...data.results] });
} catch(err) {
console.log('Fetch Error', err);
}
}
render() {
return (
<main className="cards--section">
{ this.state.data.map(Card) }
</main>
);
}
}
export default Main;
Thank you very much for reading me !
apply a scroll on a container and take the reference of the container
Use the logic below to fetch the data. This will fetch data 100 px before reaching the end
container.scrollTop + container.offsetHeight > container.scrollHeight - 100
import React, { Component } from 'react';
import Card from './Card';
class Main extends Component {
constructor(props) {
super(props);
this.url = 'https://rickandmortyapi.com/api/character';
this.handleScroll = this.handleScroll.bind(this);
this.state = {
data: [],
canLoad: true,
};
}
componentDidMount() {
this.fetchData();
}
componentWillUnmount() {
};
handleScroll(event) {
const container = event.currentTarget;
if(container.scrollTop + container.offsetHeight > container.scrollHeight - 100){
this.fetchData();
}
// get scrollY value here and call fetchData() if scroll value > 70% of height page
};
async fetchData() {
try {
const res = await fetch(this.url);
const data = await res.json();
this.setState({ data: [...this.state.data, ...data.results] });
} catch(err) {
console.log('Fetch Error', err);
}
}
render() {
return (
<main className="cards--section" onScroll={this.handleScroll}>
{ this.state.data.map(Card) }
</main>
);
}
}
export default Main;

How to export and import class properly in javascript ES6

Could someone provide me with a little bit of guidance on my class object and how to reference it in another in my project?
Here is my RequestAPI object - request-api.js (note: I understand that there isn't much going on in it yet, but I wanted to walk before I can run)
export class RequestApi {
constructor() {
this.apiBase = '../api';
}
fetch(url, options) {
var options = options || {};
return fetch(this.apiBase + url, options)
.then(_handleResponse, _handleNetworkError);
}
_handleResponse(response) {
if (response.ok) {
return response.json();
} else {
return response.json().then(function (error) {
throw error;
});
}
}
_handleNetworkError(error) {
throw {
msg: error.message
};
}
}
Here is the React Class component that i am trying to reference it in:
import React from 'react';
import { RequestApi } from '../../../../utils/request-api.js';
class UserLayout extends React.Component {
constructor() {
super();
this.state = {
users: [],
isLoading: true
};
this.addNewUser = this.addNewUser.bind(this);
this.editUser = this.editUser.bind(this);
this.deleteUser = this.deleteUser.bind(this);
}
componentDidMount() {
return RequestApi.fetch('/user')
.then(json => {
this.setState({
isLoading: false,
users: json
});
})
.catch(error => {
console.error(error.msg);
});
}
// more code here...
}
I get an error in my React Component Class object: Uncaught TypeError: _requestApi.RequestApi.fetch is not a function
Can anyone provide me with some insight/assistance?
Since fetch is not a static method, you need to create an instance of RequestApi prior to calling fetch on it:
componentDidMount() {
const api = new RequestApi();
return api.fetch('/user')
.then(json => {
this.setState({
isLoading: false,
users: json
});
})
.catch(error => {
console.error(error.msg);
});
}

React/Redux with Google Sheet API v4 is not fetching data

I've been making an app that is using the Google Sheet API and React/Redux.
If I hit the API from the component itself it works but I'm having an issue when it comes to fetch data through Redux.
This is code
Action creator:
export function fetchList() {
let data = null;
gapi.client.sheets.spreadsheets.values.get({
spreadsheetId: FULL_LIST_ID,
range: RANGE
}).then((response) => {
data = response.result.values;
}, (response) => {
throw response.result.error.message;
});
return {
type: FETCH_LIST,
payload: data
}
}
Reducer:
export default function(state = INITIAL_STATE, action = {} ) {
switch (action.type) {
case FETCH_LIST:
return { ...state, list: action.payload };
default:
return state;
}
}
Component:
import React from 'react';
import { connect } from 'react-redux';
import { fetchList } from '../../actions/index.jsx';
export class DropdownList extends React.Component {
constructor(props) {
super(props);
this.state = { res: null }
// this._fetchList = this._fetchList.bind(this);
}
componentWillMount() {
// this should fetch the data from Redux
this.props.fetchList();
// so that when
console.log(this.props);
// I should see the values attached to the payload
// instead this is fetching the data from the API hit here
this._fetchList();
}
// Here I'm hitting the API from the component
_fetchList() {
gapi.client.sheets.spreadsheets.values.get({
spreadsheetId: FULL_LIST_ID,
range: ['LIST!A1:B']
}).then((response) => {
this.setState({ res: response.result.values });
}, (response) => {
throw response.result.error.message;
});
}
_renderList() {
// this uses the values fetched locally
// return this.state.res.map((val, index) => {});
}
render() {
if (!this.state.res) {
return <div>Loading...</div>;
}
return (
<div>
{this._renderList()}
</div>
);
}
}
function mapStateToProps(state) {
return { list: state.list }
}
export default connect(mapStateToProps, { fetchList })(DropdownList);
Does anybody can help me out?
Thanks
OK, solved!
It was an issue of sync so I needed to use Redux-Thunk as a middleware in my Action Creator.

Categories