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
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;
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.
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;
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);
});
}
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.