Cannot setState - tried with Axios, AJAX and fetch() - reactjs

bit of React noob here, and this one is escaping me, so thanks in advance for what is very likely an easy fix.
All I want to do is set the state of my courses component to take in the array from my API. I'm accessing the data fine, and it's showing me the array of four objects in the console, but the state simply won't change. What am I missing?
And before anyone asks me why I'm not using Redux it's because I want to understand the fundamentals first.
import React, { Component } from 'react';
// import axios from 'axios';
import $ from 'jquery';
class CourseIndex extends Component {
constructor(){
super();
this.state = {
courses: []
}
}
componentWillMount(){
this.getCourses();
}
componentDidMount(){
this.getCourses();
}
getCourses(){
// ============================ jquery()================================
$.ajax(({
url:'/courses',
headers: {
"Authorization": localStorage.getItem('id_token')
},
dataType: 'json',
cache: false,
success: function(data){
this.setState({
courses: data
})
}.bind(this),
error: function(xhr, status, err){
console.log(err);
}
}))
console.log(this.state);
// ============================ fetch()================================
// fetch(
// '/courses',
// {
// headers: {
// "Authorization": localStorage.getItem('id_token')
// }
// })
// .then((res) => res.json())
// .then((data) => {
// this.setState({
// courses: data
// },console.log(this.state))
// });
// ============================ axios()================================
// axios
// .get(
// '/courses',
// {
// headers: {
// "Authorization": localStorage.getItem('id_token')
// }
// }
// )
// // .then(res => console.log(res.data))
// .then(res =>
// this.setState({
// courses: res
// }, console.log(this.state))
// )
// .catch(err => console.log(err));
// console.log(this.state.courses);
// const items = this.courses.map(res => (
// <li className="list-group-item">
// <h3>{ res.name }</h3>
// </li>
// ))
}
render () {
return (
<div>
</div>
)
}
}
export default CourseIndex;
Sorry for the commented out code, by the way - I was just experimenting with the different calling modules.
Thanks

$.ajax is asynchronous, so you cannot log the state before the request has finished and expect the state to have changed. setState itself is also asynchronous, so if you want to log the state after it has been changed, you can use the second argument to setState which is a callback function. You are currently invoking console.log straight away, but you want to give a function that will be invoked.
$.ajax({
url: "/courses",
headers: {
Authorization: localStorage.getItem("id_token")
},
dataType: "json",
cache: false,
success: function(data) {
this.setState(
{
courses: data
},
() => console.log(this.state)
);
}.bind(this),
error: function(xhr, status, err) {
console.log(err);
}
});

Related

API POST using fetch helper function doesn't render update after response is received

Beginner at React (and JS)...
I am trying to update text on the screen after my API helper function has completed a call. Instead, it returns empty. I have verified with the console that the data is being received. I followed the ComponentDidMount method from other similar questions but am still having no success. My code also seems to make multiple API calls, even though my intent is to only make one; I have to wonder if the issue stems from that.
Helper function:
export function apiHelper(url, data = {}, method = 'POST') {
return fetch(url, { // Return promise
method: method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
.then(res => res.json())
.then((result) => {
console.log(result);
return result;
}, (error) => {
error = error;
})
}
React Component that renders incorrectly after data is received:
class Headache extends React.Component {
constructor(props) {
super(props);
this.state = {
apiResponse: null,
};
}
componentDidMount() {
apiHelper(URLredacted,JSONredacted)
.then(response => {
this.setState({
apiResponse: response
});
console.log("state set.",response)
});
}
render() {
const jsonResponse = JSON.stringify(this.props.apiResponse)
return (
<div>
<img className="logoheader" src = {logo}/>
<ColoredLine color="grey"/>
<p>{jsonResponse}</p>
</div>
);
}
}
export function apiHelper(url, data = {}, method = 'POST') {
return fetch(url, { // Return promise
method: method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
.then(res => res.json())
.catch(err=>console.log(err))
}
second page:
class Headache extends React.Component {
constructor(props) {
super(props);
this.state = {
apiResponse: null,
};
}
componentDidMount() {
apiHelper(URLredacted,JSONredacted)
.then(response => {
this.setState({
apiResponse: response
});
console.log("state set.",response)
});
}
render() {
const jsonResponse = JSON.stringify(this.props.apiResponse)
return (
<div>
<img className="logoheader" src = {logo}/>
<ColoredLine color="grey"/>
<p>{jsonResponse && ""}</p>
</div>
);
}
}
if these code dont work you will be need asyn function because you need to wait to fetch data.

How to save single object into state, from json end point axios

UPDATE:
axios
.get("https://cors-anywhere.herokuapp.com/" + "https://api.linkedin.com/v2/me", config)
.then(response => {
this.setState({profile: response.data})
})
^ saved the object in state for me :) Thanks everyone!!
I am a newbie to react. I am trying to save a single object from a JSON end point into the state of my react component. I am definitely returning the JSON data in the response. However it is not being saved into the state, can you see where I am going wrong?
// State needed for the component
constructor(props) {
super(props);
this.state = {
profile: {},
};
}
// Grabs profile data from the json url
private getProfile() {
let config = {
headers: {'Authorization':'Bearer AQVVEqNXTWV....'}
}
axios
.get("https://cors-anywhere.herokuapp.com/" + "https://api.linkedin.com/v2/me", config)
.then(response =>
response.data(profile => ({
id: `${ profile.id }`
}))
)
.then(profile => {
this.setState({
profile
});
})
// We can still use the `.catch()` method since axios is promise-based
.catch(error => this.setState({ error, isLoading: false }));
}
JOSN data returned:
{
"localizedLastName": "King",
"id": "fm0B3D6y3I",
"localizedFirstName": "Benn"
}
Your first then block looks wrong.
Try to do console.log there like this:
.then(response => {
console.log(response); // I am sure that you will get profile inside response.data or something similar
return response.data(profile => ({
id: `${ profile.id }`
}));
})
If you want to keep your first then that "prepares the data", then you should return a promise instead of data, like:
let config = {
headers: {'Authorization':'Bearer AQVVEqNXTWV....'}
}
axios
.get("https://cors-anywhere.herokuapp.com/" + "https://api.linkedin.com/v2/me", config)
.then(response => {
return new Promise((resolve, reject) => {
resolve( {
id: `${ response.data.id }`
});
});
}
)
.then(profile => {
this.setState({
profile
});
})
// We can still use the `.catch()` method since axios is promise-based
.catch(error => this.setState({ error, isLoading: false }));
Here's an example of how that would work:
I do believe that's a bit of an overkill though and you should be able to just set your state in the first then such as:
this.setState({profile: {id : response.data.id}});
Try to remove the second then, like this:
axios
.get("https://cors-anywhere.herokuapp.com/" + "https://api.linkedin.com/v2/me", config)
.then(response => {this.setState({ profile: response.data })};
})
}))

setState not working with forloop in react function

I am nesting two api calls inside componentDidMount, everything working fine, the only issue I have is the state do not update so I put some console logs to see what's going on
fetch reviews done!
analysis done!
false
analysis done!
false
analysis done!
false
As you can see the state of loaded never get updated and by the way no data show up on the application, I probably messed up the logic with this function but I can't figure this out.
componentDidMount = () => {
this.setState({ loading: true });
fetch(
"https://url-one.com",
{
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"X-Spree-Token": "xxx"
}
}
)
.then(response => response.json())
.then(responseJson => {
console.log('fetch reviews done!')
this.setState(
{
list: responseJson.reviews,
},
() => {
var obj = this.state.list;
var data = [];
for (let i in obj) {
fetch(
"https://url-two.com",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
api_key: "uuu",
data: obj[i].text
})
}
)
.then(response => response.json())
.then(responseJson => {
data.push({'review': obj[i].text, 'analysis': responseJson.results * 100});
});
this.setState({
data: data,
loaded: true,
loading: false,
});
console.log('analysis done!')
console.log(this.state.loaded)
}
}
);
});
}
Of course if I use a separate function to update the state it works!
show = () => {
this.setState({ loaded: true });
};
As you can see the state of loaded never get updated
Because the setState happens asynchronous (not immediately update), using console.log(this.state.loaded) like that won't work as expected, instead, you might use the setState callback as you did with the second fetch, like so:
this.setState(
{
data: data,
loaded: true,
loading: false
},
() => {
console.log('analysis done!');
console.log(this.state.loaded);
}
);
EDIT
I think we should use Promise.all() to make it work, like this:
componentDidMount() {
this.setState({ loading: true });
fetch('https://url-one.com', {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'X-Spree-Token': 'xxx'
}
})
.then(response => response.json())
.then(responseJson => {
console.log('fetch reviews done!');
this.setState(
{
list: responseJson.reviews
},
() => {
var obj = this.state.list;
var data = [];
var fetchArr = [];
for (let i in obj) {
let promise = fetch('https://url-two.com', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
api_key: 'uuu',
data: obj[i].text
})
}).then(response => response.json());
fetchArr.push(promise); // make an array of promises
}
Promise.all(fetchArr).then(values => { //after all promises resolved, we'll receive an array of responseJson, we'll loop through it
values.forEach((responseJson, i) => { //for each responseJson, we push it to the data array
data.push({
review: obj[i].text,
analysis: responseJson.results * 100
});
});
// finally, we update state
this.setState(
{
data: data,
loaded: true,
loading: false
},
() => {
console.log('analysis done!');
console.log(this.state.loaded);
}
);
});
}
);
});
}
You have a couple conflicting processes here that need to get shored up. You don't want to modify state during async actions because internally you will fire off a re-render, so I'd suggest reorganizing a bit. The loaded state is not resolving correctly because you aren't waiting for your subsequent requests to finish. Here is an example:

React API returns empty

fairly new to react but I have the following API data I want to create as a list or whatever:
https://jsonblob.com/53c7f296-d79d-11e8-839a-a312b719c60a
My react component looks like this:
class Contacts extends Component {
constructor(props) {
super(props)
this.state = {
contacts:[]
}
}
componentDidMount() {
fetch('https://api.billysbilling.com/v2/contacts?organizationId=kZeGqbBRSXyeeDoWNkF3jQ',{
headers: {
'X-Access-Token': API_KEY,
'Content-Type': 'application/json'
},
})
.then(response => {
return response.json();
})
.then(response => console.log(response))
.then(d => {
this.setState({ contacts: d });
console.log("state", this.state.contacts)
})
}
render() {
return (
<div>
{
this.state.contacts.map(((contact, index) =>
<th key={`${contact.contact}${index}`}>
<div>
<div>
{contact.contact}
</div>
</div>
</th>
))
}
</div>
);
}
But however it seems to return nothing.
The console.log actually shows the data, so I am pretty stuck.
It would be awesome if some of you could help.
The state also just returns an empty array in the react tools in chrome.
When you write then(response => console.log(response)), you are not returning anything, so d will be undefined in the function given to the following then.
You could write it like this instead:
fetch('https://api.billysbilling.com/v2/contacts?organizationId=kZeGqbBRSXyeeDoWNkF3jQ',{
headers: {
'X-Access-Token': API_KEY,
'Content-Type': 'application/json'
},
})
.then(response => {
return response.json();
})
.then(d => {
console.log(d);
this.setState({ contacts: d.contacts });
});

How to make a rest post call from ReactJS code?

I am new to ReactJS and UI and I wanted to know how to make a simple REST based POST call from ReactJS code.
If there is any example present it would be really helpful.
Straight from the React Native docs:
fetch('https://mywebsite.example/endpoint/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})
(This is posting JSON, but you could also do, for example, multipart-form.)
Also see docs for ReactJS AJAX FAQs if not using React Native.
React doesn't really have an opinion about how you make REST calls. Basically you can choose whatever kind of AJAX library you like for this task.
The easiest way with plain old JavaScript is probably something like this:
var request = new XMLHttpRequest();
request.open('POST', '/my/url', true);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
request.send(data);
In modern browsers you can also use fetch.
If you have more components that make REST calls it might make sense to put this kind of logic in a class that can be used across the components. E.g. RESTClient.post(…)
Another recently popular packages is : axios
Install : npm install axios --save
Simple Promise based requests
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
you can install superagent
npm install superagent --save
then for make post call to server
import request from "../../node_modules/superagent/superagent";
request
.post('http://localhost/userLogin')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ username: "username", password: "password" })
.end(function(err, res){
console.log(res.text);
});
As of 2018 and beyond, you have a more modern option which is to incorporate async/await in your ReactJS application. A promise-based HTTP client library such as axios can be used. The sample code is given below:
import axios from 'axios';
...
class Login extends Component {
constructor(props, context) {
super(props, context);
this.onLogin = this.onLogin.bind(this);
...
}
async onLogin() {
const { email, password } = this.state;
try {
const response = await axios.post('/login', { email, password });
console.log(response);
} catch (err) {
...
}
}
...
}
I think this way also a normal way. But sorry, I can't describe in English ((
submitHandler = e => {
e.preventDefault()
console.log(this.state)
fetch('http://localhost:5000/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
}
https://googlechrome.github.io/samples/fetch-api/fetch-post.html
fetch('url/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
Here is a the list of ajax libraries comparison based on the features and support.
I prefer to use fetch for only client side development or isomorphic-fetch for using in both client side and server side development.
For more information on isomorphic-fetch vs fetch
Here is a util function modified (another post on stack) for get and post both. Make Util.js file.
let cachedData = null;
let cachedPostData = null;
const postServiceData = (url, params) => {
console.log('cache status' + cachedPostData );
if (cachedPostData === null) {
console.log('post-data: requesting data');
return fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
})
.then(response => {
cachedPostData = response.json();
return cachedPostData;
});
} else {
console.log('post-data: returning cachedPostData data');
return Promise.resolve(cachedPostData);
}
}
const getServiceData = (url) => {
console.log('cache status' + cachedData );
if (cachedData === null) {
console.log('get-data: requesting data');
return fetch(url, {})
.then(response => {
cachedData = response.json();
return cachedData;
});
} else {
console.log('get-data: returning cached data');
return Promise.resolve(cachedData);
}
};
export { getServiceData, postServiceData };
Usage like below in another component
import { getServiceData, postServiceData } from './../Utils/Util';
constructor(props) {
super(props)
this.state = {
datastore : []
}
}
componentDidMount = () => {
let posturl = 'yoururl';
let getdataString = { name: "xys", date:"today"};
postServiceData(posturl, getdataString)
.then(items => {
this.setState({ datastore: items })
console.log(items);
});
}
Here is the simple method to define and call post APIs in reactjs. Install axios using command npm install axios and call post req method wherever you want, it will return array that contains 100 elements.
// Define post_req() Method in authAction.js
import axios from 'axios';
const post_req = (data) => {
return new Promise((resolve, reject) => {
const url = 'https://jsonplaceholder.typicode.com/posts'
const header = {
"Access-Control-Allow-Origin": "*",
"Content-Type: application/json"
}
axios({
method: 'post',
url: url,
data: data,
headers: header
});
.then((res)=>{resolve(res);})
.catch((err)=>{reject(err);})
})
}
// Calling post_req() Method in react component
import React, { Component } from 'react';
import { post_req } from 'path of file authAction.js'
class MyReactComponent extends Component {
constructor(props) {
super(props);
this.state = {
myList:[]
};
}
componentDidMount() {
let data = {
.......
}
this.props.post_req(data)
.then((resp)=>{this.setState({myList:resp.data})})
.catch((err)=>{console.log('here is my err',err)})
}
render() {
return (
<div>
....
</div)
}
}
export default MyReactComponent;
import React ,{useState}from 'react';
import Axios from 'axios';
export default function Formlp()
{
const url ="";
const [state, setstate] = useState({
name:"",
iduser:""
})
function handel(e){
const newdata={...state}
newdata[e.target.id]=e.target.value
setstate(newdata);
}
function submit(e)
{
e.preventDefault();
// Axios.post(url,{name:state.name,iduser:state.iduser}).then( res=>{console.log(res)});
console.log(state)
}
return (
<div onSubmit={ (e)=> submit(e)}>
<input onChange={ (e)=>handel(e) } id="name" value={state.name} placeholder="name" type="text" >
<input onChange={ (e)=>handel(e) } id="iduser" value={state.iduser} placeholder="iduser" type="text" >
<button>submit</button>
</form>
</div>
);
}
Here is a quick example for v18+ while handling form data and creating a POST request with the data.
async function handleOrderSubmit(event){
event.preventDefault()
try{
const formData= {name: event.target.name.value, email: event.target.email.value, message: event.target.name.message}
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
};
const response = await fetch('https://www.example.com/form', requestOptions);
const data = await response.json();
navigate("/form-response", { state: {data: data, status: true} })
}
catch(error){
navigate("/form-response", { state: {status: false} })
}
}
Note 1: Using status on '/form-response' page, you can customise what to show user. For true, you can show a different section and for false a different one.
Note 2: If the status is successful, you can access data on the next page also and customise it according to user information.
Note 3: event.preventDefault() is important to avoid page reloading.
Here is an example: https://jsfiddle.net/69z2wepo/9888/
$.ajax({
type: 'POST',
url: '/some/url',
data: data
})
.done(function(result) {
this.clearForm();
this.setState({result:result});
}.bind(this)
.fail(function(jqXhr) {
console.log('failed to register');
});
It used jquery.ajax method but you can easily replace it with AJAX based libs like axios, superagent or fetch.

Resources