How do I change a state after getting data from API? - reactjs

constructor(props) {
super(props);
this.state = {
message: ""
};
}
async getData() {
this.setState({...this.state})
await axios.get("https://g...")
.then(function(response) {
console.log(response);
this.setState({message: response.data})
}).bind(this)
}
render() {
return (
<div>
{this.state.message}
</div>
);
}
I tried to use this code to get data from the API. However, the message that is printed out is only linked to the original constructor, and the getData() function does not change the state. How should I go around changing the state after getting data?

You should use componentDidMount, and put the function requesting data in componentDidMount life circle.
By the way, you can add a loading to enhance the user experience : )
import React from 'react';
import "./styles.css";
const BASE_URL = 'https://api.github.com';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
message: ''
}
}
componentDidMount() {
this.getData();
}
async getData() {
try {
const result = await fetch(`${BASE_URL}/repos/facebook/react`);
const toJson = await result.json();
const stringify = JSON.stringify(toJson, null, 2);
this.setState({
message: stringify
})
} catch (error) {
// ignore error.
}
}
render() {
const { message } = this.state;
return (
<div>
{message}
</div>
)
}
}
export default App;

If you are using 'async' and 'await' you don;t have to use then() function
you can write
const data = await axios.get("url")
console.log(data.data)
this.setState({message:data.data})

Related

How to pass props to API URL in React js?

i'm new to React and I need help with passing props to API URL. I have two class components -> (MyClass) works fine. However when I use variable from MyClass as props in other class component (MyOtherClass), it seems to work only in "render" part. I mean <div> variable: {variable}, url : {url2}</div> is shown in app as expected but when I try to pass this variable from props to API URL, it is not working and instead the URL looks like this: "http://localhost:55111/status/[object Object]". Any ideas what might cause the problem??
Here's my code:
import React, { Component } from 'react'
import axios from 'axios'
export default class MyClass extends Component {
constructor(props) {
super(props);
this.state = {
data: {}
}
}
componentDidMount() {
axios
.get("http://localhost:55111/start")
.then(response => {
this.setState({
data: response.data
});
console.log(this.state.data);
})
.catch(err => {
this.err = err;
});
}
render() {
const variable = this.state.data.sent
return (
<div>
<h1>Hello worlds</h1>
<p>var: {variable}</p>
<MyOtherClass variable={variable} />
</div>
);
}
}
This is the other class component causing troubles:
class MyOtherClass extends Component {
constructor(props) {
super(props);
this.state = {
data: {}
};
}
async componentDidMount() {
const {variable} = this.props
axios.get(`http://localhost:55111/status/${variable}`)
.then(response => {
this.setState({
data: response
});
console.log(this.state);
})
render() {
const { variable } = this.props
const url2 = `http://localhost:55111/status/${variable}`
return (
<div>variable: {variable}, url : {url2}</div>
);
}
}
import React, { Component } from 'react'
import axios from 'axios'
export default class MyClass extends Component {
constructor(props) {
super(props);
this.state = {
data: {}
}
}
componentDidMount() {
this.getData()
}
async getData() => {
const response = await axios.get("http://localhost:55111/start")
this.setState({data: response.data})
}
render() {
const variable = this.state.data.sent
return (
<div>
<h1>Hello worlds</h1>
<p>var: {variable}</p>
<MyOtherClass variable={variable} />
</div>
);
}
}
Use the async await.

How to pass parameters in React Function From 1 file to another

I am newbie to reactjs and I would like to ask if it is possible to achieve this.
I have two files, I would like to pass the ID from Home.js to DataModel.js
Heres my code:
DataModel.js
const axios = require('axios');
const base_url = 'https://jsonplaceholder.typicode.com';
function getUSers(id) {
return axios.get(base_url + '/users/' + id)
}
export const getUSers = getUSers(id);
=================================
Home.js
import { getUSers } from './DataModels';
class Home extends Component {
constructor(props){
super(props);
this.state = {
records: ''
}
}
render(){
let id = 2;
getUsers(id); // -----> How to pass this ID?
return (
<div>
//Codes
</div>
);
}
}
Assuming your DataModel.js exists in the same origin src folder as your component. You can minimize your file by using some ES6 JavaScript.
import axios from "axios"
const base_url = 'https://jsonplaceholder.typicode.com';
export const getUsers = (id) => {
return axios.get(base_url + '/users' + id)
}
Then in Home.js you should call that function in componentDidMount() which is the React life-cycle method that is triggered after the component has first rendered (after first displaying the content).
import { getUsers } from './DataModels';
class Home extends Component {
constructor(props){
super(props);
this.state = {
records: ''
}
}
componentDidMount(){
let id = 2
getUsers(id)
.then((res) => {
this.setState({
records: res.data
})
})
}
render(){
return (
<div>
//Codes
</div>
);
}
}
Add your fetch in componentDidMount().
// Data Model
function getUsers(id) {
return axios.get(base_url + '/users' + id) // return a promise
}
export const getUsers; // named-export function
// Component
class Home extends Component {
...
async componentDidMount() {
let id = 2; // for sample use only
const users = await getUsers(id);
console.log(users); // verify if fetched correctly
}
...
}
Do not put any side effects in render() that can alter the state of the component. Say if you store user in state variable.
this.state = {
users: {},
}
async fetch = id => {
const users = await getUsers(id)
this.setState({ users }) // altering state.users
}
render() {
fetch(2) // BAD: should not be inside render.
// This will cause many re-renders if you alter state.users
}

React + Axios - Map returns is not a function?

I'm working on my first API with React. I am able to console log my current state after its loaded and the state for that array is set. However, running my component with a prop "FragrancesArray" which is set after loading the data from this.state.fragrances returns in not a function.
Using axios async and await.
No idea why? Can someone help?
Thanks.
My code:
// Core React
import React, { Component } from 'react';
// Axios
import axios from 'axios';
// Constants
import { FRAGRANCES_URL, BLOGS_URL, MAKE_UP_URL } from 'constants/import';
// Components
import Fragrances from 'components/Fragrances/Fragrances';
class App extends Component {
state = {
fragrances: [],
blogs: [],
makeup: []
}
getCoffee() {
return new Promise(resolve => {
setTimeout(() => resolve('☕'), 0); // it takes 1 seconds to make coffee
});
}
async showData() {
try {
// Coffee first
const coffee = await this.getCoffee();
console.log(coffee); // ☕
// Axios API's
const fragranceData = axios(FRAGRANCES_URL);
const blogData = axios(BLOGS_URL);
const makeupData = axios(MAKE_UP_URL);
// await all three promises to come back and destructure the result into their own variables
await Promise.all([fragranceData, blogData, makeupData])
.then((data) => {
this.setState({
fragrances: data[0],
blogs: data[1],
makeup: data[2]
});
const { blogs } = this.state;
console.log(blogs);
})
} catch (e) {
console.error(e); // 💩
}
}
componentDidMount() {
this.showData();
}
render() {
return (
<Fragrances FragranceArray={this.state.fragrances} AppURL={FRAGRANCES_URL} />
)
}
}
export default App;
In react, before you can set/use state, you need to declare it with getInitialState() but with ES6 class model you initialize state in a constructor.
class App extends Component {
constructor(props) {
super(props)
//- Initialize default state values
this.state = {
fragrances: [],
blogs: [],
makeup: []
}
}
//The rest of code stays the same.
render() {
return (
<Fragrances FragranceArray={this.state.fragrances} AppURL={FRAGRANCES_URL} />
)
}
}
More about React state

React: Http request response not displaying in render()

Can someone tell me what is wrong with my code below? I am making an HTTP request to Darksky API using 'superagent' and then trying to display the result in an h2 which isn't working. I tried logging it to console and it works perfectly but if I am trying to display it on the page it doesn't work. Could someone help me out pls, I am new to react and not sure what is going wrong.
import React, { Component } from "react";
import "./Body.css";
import Request from "superagent";
class Body extends Component {
constructor() {
super();
this.getData = this.getData.bind(this);
}
getData() {
var url = this.props.apiUrl;
Request.get(url)
.then(response => {
return(JSON.stringify(response.currently.summary));
})
.catch(error => {});
}
render() {
<div>
<h2>
{this.getData()}
</h2>
</div>
}
}
export default Body;
This is the other file where I am importing Body.js :-
import React, { Component } from "react";
import Body from "./Body";
import "./App.css";
class App extends Component {
render() {
return <Body
apiUrl="https://api.darksky.net/forecast/42a9693aecf45c358afbda0022c5cf65/28.5355,77.3910" />;
}
}
export default App;
You need to set your data in the state of the component, it fire new render:
constructor() {
super();
this.getData = this.getData.bind(this);
this.state = {data: {}}
}
componentDidMount() {
var url = this.props.apiUrl;
Request.get(url)
.then(response => this.setState({data: JSON.stringify(response.currently.summary)}))
.catch(error => {});
}
render(){
console.log("your data", this.state.data);
return <div>test</div>;
}
And work with this data with this.state.data.
I advise you to change getData() function to componentDidMount mehtod.
You should use a life cycle method(componentDidMount) with the use of state. It is recommended to make HTTP calls inside the componentDidMount() method.
constructor() {
super();
this.state = {
result: ''
};
}
componentDidMount(){
var url = this.props.apiUrl;
Request.get(url)
.then(response => {
this.setState({
result: JSON.stringify(response.currently.summary)
});
})
.catch(error => {});
}
render() {
<div>
<h2>
{this.state.result}
</h2>
</div>
}

beginner at react.js - rendering component from state which is updated later

I'm trying to test rendering a list component from an JSON object called with fetch, however I suspect the render is called before the JSON is returned as I get an undefined error. Note the debug alert() gets the value, but the render has already error on undefined. How do I handle this? Is there a way to call the render function after the data has been fetched? OR could how would I get the data to render with '?' and then update when the data arrives? Note my if (!object) doesn;t work when called as an inline wrapper - why not - or more impoartanly how would I achive this? Sorry for the begginer questions - I suspect I meant to be using a data framework to bring data for react to display but I wanted to start learning with less frameworks and get the basics. Many thanks! - code is:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class ItemLister extends React.Component {
constructor(props ) {
super(props);
this.state = { items: [] };
}
componentDidMount() {
let url = "http://localhost:8888";
let iterator = fetch(url, {method: 'GET'});
iterator
.then(response => {
//console.log('sss', response)
return response.json();
})
.then(post => {
//console.log(post)
this.state.items = post;
alert(this.state.items.users[3].firstname);
});
}
output(object){
if (!object){
return '?';
}else{
return object;
}
}
render() {
return(
<div>
<div>Items:</div>
<div>{this.output(this.state.items.users[3].firstname)}</div>
</div>
);
}
}
export default ItemLister;
your render function could be something like this:
render() {
const username = (this.state.items === []) ? placeholder : this.output(this.state.items.users[3].firstname;
return(
<div>
<div>Items:</div>
<div>{username}</div>
</div>
);
}
basically, you render a placeholder component until your data arrives, since your data fetch is async and in componentDidMount, so your render will happen initially before you have data.
although you probably want to rethink how this component is constructed in general, why are you accessing specifically users[3]?
Try this code it will help you
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
class ItemLister extends Component {
constructor(props) {
super(props);
this.state = { items: [], firstname: "" };
}
componentDidMount() {
let url = "http://localhost:8888";
let iterator = fetch(url, { method: "GET" });
iterator
.then(response => {
//console.log('sss', response)
return response.json();
})
.then(post => {
//console.log(post)
this.setState({
items: post,
firstname: this.state.items.users[3].firstname
});
alert(this.state.items.users[3].firstname);
});
}
output(object) {
if (!object) {
return "?";
} else {
return object;
}
}
render() {
return (
<div>
<div>Items:</div>
<div>{this.state.firstname}</div>
</div>
);
}
}
export default ItemLister;

Resources