How can I use a state in a url to make a get using axios in reactjs - javascript

I am using axios in react to get information from a django backend, I am getting the user data and I am storing it in a state in the component but I want to use one of the attributes in the user_data state in the url of another get to get more information from the backend, I do not know if I explained it correctly but here is the code :
state = {
user_data: [],
classes: []
}
componentDidMount() {
const config = {
headers: {
'Content-Type': 'application/json',
'Authorization': `JWT ${localStorage.getItem('access')}`,
'Accept': 'application/json'
}
};
axios.get(`${process.env.REACT_APP_API_URL}/auth/users/me/`, config)
.then(
res => {
this.setState({
user_data: res.data
});
}
)
const myString = this.state.user_data.SectionNumber
axios.get(`${process.env.REACT_APP_API_URL}/Elearning/Classes/${myString}`, config)
.then(
res => {
this.setState({
classes: res.data
});
console.log(res.data);
}
)
}
I do not know how to change the state object into something that axios can understand and use in the url

At this point when you are fetching the user related data you do not need to depend on the state. You can pass the second call as a callback to the first setState so that it can update it when the promise resolves and state has been updated.
axios.get(`${process.env.REACT_APP_API_URL}/auth/users/me/`, config)
.then(
res => {
this.setState({
user_data: res.data
});
}, () => {
const myString = this.state.user_data.SectionNumber
axios.get(`${process.env.REACT_APP_API_URL}/Elearning/Classes/${myString}`, config)
.then(
res => {
this.setState({
classes: res.data
});
console.log(res.data);
}
)
}
)

You don't need to set the state and then take from the state to use this parameter in your url. You can use promises and pseudo-synchronous code async/await and it should help.
async componentDidMount() {
const config = {
headers: {
'Content-Type': 'application/json',
'Authorization': `JWT ${localStorage.getItem('access')}`,
'Accept': 'application/json'
}
};
const userDataResponse = await axios.get(`${process.env.REACT_APP_API_URL}/auth/users/me/`, config)
const myString = userDataResponse.data.SectionNumber;
const classesResponse = await axios.get(`${process.env.REACT_APP_API_URL}/Elearning/Classes/${myString}`, config)
this.setState({
user_data: userDataResponse.data,
classes: classesResponse.data
});
}

This is the code that worked with me
axios.get(`${process.env.REACT_APP_API_URL}/auth/users/me/`, config)
.then(
res => {
this.setState({
user_data: res.data
});
const SectionNumber = this.state.user_data.SectionNumber
axios.get(`${process.env.REACT_APP_API_URL}/Elearning/Classes/${SectionNumber}`, config)
.then(
res => {
this.setState({
classes: res.data
});
}
)
}
)

I am also facing a similar problem and i have done exactly as you have shown but I do not see the results.
axiosInstance.get('/user/profile/' + this.state.adminCard).then(response => {
axiosInstance.defaults.headers['Authorization'] = "JWT " + response.data.access;
this.setState({
fullName: response.data.lastName + ", " + response.data.firstName,
diploma: response.data.diploma,
projectSlug: response.data.project
})
}, () => {
const slug = this.state.projectSlug;
axiosInstance.get('/user/project/' + slug).then(response => {
axiosInstance.defaults.headers['Authorization'] = "JWT " + response.data.access;
this.setState({
assignedProjectName: response.data.projectName,
assignedProjectDesc: response.data.projectDesc,
assignedProjectSupervisor: response.data.projectSupervisor
})
console.log(this.state.assignedProjectName)
})
})
On the line where I console.log(this.state.assignedProjectName), I do not even get a return, please advice.

Related

How do I handle an API response with useState to update a state?

I am working on an API response. My aim is to take this API response to update a specified state.
Here the neccessary code snippet from my functional componenet:
const [recordImagesPayload, setRecordImagesPayload] = useState([]);
useEffect(() => {
const headers = { 'Content-Type': 'application/json' };
// const payload = JSON.stringify({ ...createPayload(), recordImage: newImage });
request(`${url}`, { headers, method: 'GET' })
.then((response: any) => response.json())
.then(json => {
var obj = JSON.parse(json);
var res: any = [];
for (var i in obj) {
res.push(obj[i]);
}
setRecordImagesPayload(res);
console.log(res);
});
}, []);
My console.is not showing the res from my last line of code. I am probably doing something wrong with the response but I don't know what to do.
Please help.
Thanks in advance. :)
I assume the request function is using fetch function, in that case you are already parsing the json response using response.json() call, so the resolved value in the next then is not json, so you don't have to use JSON.parse there
Try running this. Here instead of creating a new array and for loop, we can just use Object.values
useEffect(() => {
const headers = { 'Content-Type': 'application/json' };
// const payload = JSON.stringify({ ...createPayload(), recordImage: newImage });
request(`${url}`, { headers, method: 'GET' })
.then((response: any) => response.json())
.then(result => {
const res = Object.values(result);
setRecordImagesPayload(res);
console.log(res);
});
}, []);
Thanks #Akhil. I had a minor issue in my code regarding Typescript which was leading to the issue. The type of the result wasn't specified, but beside that, Akhil's answer was very accurate. Many thanks for the quick response and support.
Here is the final code which worked for me:
useEffect(() => {
const headers = { 'Content-Type': 'application/json' };
// const payload = JSON.stringify({ ...createPayload(), recordImage: newImage });
request(`${url}`, { headers, method: 'GET' })
.then((response: any) => response.json())
.then(result: any => {
const res = Object.values(result);
setRecordImagesPayload(res);
console.log(res);
});
}, []);

Axios and response data set split to multiple arrays

I'm trying to get data from an API using axios command like
function fetchData(apiURL){
let data = [];
let options = {
method: "GET",
url: apiURL,
headers: {
"Access-Control-Allow-Origin": "*"
},
credentials: "include"
};
axios(options)
.then(response => {
data = response.data;
console.log(data);
})
.catch(function (error) {
console.log("System error : " + error);
});
return data;
}
but that will produce sets of arrays which will store arrays of JSONs from response.data in count of 100 per array set.
I haven't had problem using fetch() to retrieve all data. How I can get similar response of one large array of JSON objects instead of a split?
PS.
I have triggered that function in the
componentDidMount() {
const apiURL = process.env.REACT_APP_API;
let tableData = fetchData(apiURL);
console.log("DATA " + JSON.stringify(tableData));
this.setState({tblData : tableData});
}
Axios requests are asynchronous and return promises, so you need to adjust your example a bit so that your function returns a promise.
/**
* #return {Promise<T>}
*/
function fetchData(apiURL){
const options = {
method: "GET",
url: apiURL,
headers: {
"Access-Control-Allow-Origin": "*"
},
credentials: "include"
};
return axios(options)
.then(response => {
return response.data;
})
}
Now, when you consume this API do so asynchronously.
function somethingThatUpdatesThatUI() {
fetchData("/api/foo/bar")
.then((data) => {
//perform updates to UI or state here
})
.catch((err) => {
//alert the users that an error has happened here
})
}
You can update the componentDidMount function:
componentDidMount() {
const apiURL = process.env.REACT_APP_API;
fetchData(apiURL).then(data => {
console.log(data ${JSON.stringify(tableData)})
this.setState({tblData : data});
})
}

Problem with nested fetch request in React

New to React, I'm currently trying to create a data table with data from an API.
I want to have a first fetch, and then run another with response from the first (id) in order to complete my table.
Here is my code :
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {},
data: []
};
}
componentDidMount() {
this.setState({
user: JSON.parse(localStorage.getItem('user'))
}, function () {
this.loadAllObjectsInfo()
});
}
// Fetch all object info in order to fill the table
loadAllObjectsInfo() {
const requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'bbuser': this.state.user.userId,
'bbtoken': this.state.user.secret
},
};
fetch('https://xxxxx/api/objects', requestOptions)
.then(response => response.json())
.then((data) => {
this.setState({ data: data })
})
}
With this code, I have the data I want to render my table but I need to run another fetch to get other info with the id coming from the first request.
How can I do that nested fetch request ?
Thanks a lot,
Matthieu
You can easily manage this with async/await:
async loadAllObjectsInfo() {
const requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'bbuser': this.state.user.user
'bbtoken': this.state.user.secret
},
};
let response = await fetch('https://xxxxx/api/objects', requestOptions);
let data = await response.json();
// here is another fetch - change to fit your request parameters (this is just example)
let info = await fetch('https://xxxxx/api/objects/' + data.id);
this.setState({ data });
}
You can read more about async function.
#JourdanM, you should return a new fetch request from one of the then handlers. I've made a simple snippet for you. There are no data validators and spinners. This is a simple showcase. =)
A fetch request returns a promise, and you can chain promises by simply returning them from the then handlers. Here is a good article about it, it has great examples: https://javascript.info/promise-chaining
function fetchUser (user) {
return fetch(`https://api.github.com/users/${user.login}`)
}
class User extends React.Component {
state = {
user: null
}
componentDidMount () {
fetch("https://api.github.com/users")
.then(response => response.json())
.then(users => fetchUser(users[0]))
.then(response => response.json())
.then(user => {
this.setState({user})
})
}
render () {
return (
<div>
<pre>{JSON.stringify(this.state.user, null, 2)}</pre>
</div>
)
}
}
ReactDOM.render(<User />, document.querySelector("#root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You can write the code as below.
fetch('https://xxxxx/api/objects', requestOptions)
.then(response => response.json())
.then((res1) => {
fetch('https://xxxxx/api/objects', requestOptions)
.then(response => response.json())
.then((res2) => {
this.setState({ data: res2 });
});
});
Hope this will work for you!
You can also use axios like below
axios.post(url, data, header).then(res => {
if(res.status === 200){
console.log('1st data')
axios.post(url, data, header)
.then(response => {
if (response.status === 200) {
console.log('2nd data')
} else {
console.log('2nd error')
}
});
}else{
console.log('1st error')
}
});

How do we get value from inside the arrow function on outer scope?

I have the following code which requests from api and gets data in response. How can I get assigned variables inside arrow function i.e. priceEvents, defaultDate etc after all the api request and set state after that? Is it a good approach on setting state after all the api requests?
axios.get(`/api/v1/test/prices?date_from=${ currentDate.format() }`, { headers: headers })
.then((response) => {
const priceEvents = response.data;
const defaultDate = this.cal.$calendar.fullCalendar("getDate");
//this.setState({ priceEvents, defaultDate });
})
.then((response) => {
return axios.get(`/api/v1/test/events?date_from=${ currentDate.format() }`, { headers: headers })
})
.then((response) => {
const bookingEvents = response.data;
//this.setState({ bookingEvents });
});
console.log(bookingEvents);
console.log(priceEvents);
You need to pass the values along from one promise to another:
axios.get(`/api/v1/test/prices?date_from=${ currentDate.format() }`, { headers: headers })
.then((response) => {
return {priceEvents: response.data}
})
.then(({priceEvents}) => {
return axios.get(`/api/v1/test/events?date_from=${ currentDate.format() }`, { headers: headers })
.then(response => {
return {priceEvents, bookingEvents: response.data}
})
})
.then(({priceEvents, bookingEvents}) => {
const defaultDate = this.cal.$calendar.fullCalendar("getDate");
this.setState({ priceEvents, bookingEvents, defaultDate });
console.log(bookingEvents);
console.log(priceEvents);
});
You could also use await. It's a bit cleaner in this situation.
async function doStuff() {
const {data: priceEvents} = await axios.get(`/api/v1/test/prices?date_from=${ currentDate.format() }`, { headers: headers })
const {data: bookingEvents} = await axios.get(`/api/v1/test/events?date_from=${ currentDate.format() }`, { headers: headers })
const defaultDate = this.cal.$calendar.fullCalendar("getDate");
this.setState({ priceEvents, bookingEvents, defaultDate }); // 'this' may not refer to your react component in this case
console.log(bookingEvents);
console.log(priceEvents);
}
doStuff()
Also, since the two axios requests don't depend on each other, you could run them in parallel:
Promise.all([
axios.get(`/api/v1/test/prices?date_from=${ currentDate.format() }`, { headers: headers }),
axios.get(`/api/v1/test/events?date_from=${ currentDate.format() }`, { headers: headers }),
])
.then(([priceResponse, eventsResponse]) => {
return {
priceEvents: priceResponse.data,
bookingEvents: eventsResponse.data,
}
})
.then(({priceEvents, bookingEvents}) => {
const defaultDate = this.cal.$calendar.fullCalendar("getDate");
this.setState({ priceEvents, bookingEvents, defaultDate });
console.log(bookingEvents);
console.log(priceEvents);
});

localstorage.getitem('key') sometimes returns null - in a react app

this is a very weird problem! I'm trying to build a login form which sets a JWT token in localstorage. Other forms then use that token to post requests. I can see the token in my console.log just fine, but sometimes (like 3 out of 5 times), when I am setting localstorage.getitem('idToken'), it shows as null. This behavior most noticeably happens when I remove the console.log(idToken) from my loginUser() function (code in actions.js file - given below). What am I doing wrong? my app is built using React/Redux.
action.js
export function loginUser(creds) {
const data = querystring.stringify({_username: creds.username, _password: creds.password});
let config = {
method: 'POST',
headers: { 'Content-Type':'application/x-www-form-urlencoded' },
body: data
};
return dispatch => {
// We dispatch requestLogin to kickoff the call to the API
dispatch(requestLogin(creds));
return fetch(BASE_URL+'login_check', config)
.then(response =>
response.json().then(user => ({ user, response }))
).then(({ user, response }) => {
if (!response.ok) {
// If there was a problem, we want to
// dispatch the error condition
dispatch(loginError(user.message));
return Promise.reject(user)
} else {
localStorage.setItem('idToken', user.token);
let token = localStorage.getItem('idToken')
console.log(token);
// if I remove this log, my token is returned as null during post.
dispatch(receiveLogin(user));
}
}).catch(err => console.log("Error: ", err))
}
}
here's my POST request:
import axios from 'axios';
import {BASE_URL} from './middleware/api';
import {reset} from 'redux-form';
let token = localStorage.getItem('idToken');
const AuthStr = 'Bearer '.concat(token);
let headers ={
headers: { 'Content-Type':'application/json','Authorization' : AuthStr }
};
export default (async function showResults(values, dispatch) {
console.log(AuthStr);
axios.post(BASE_URL + 'human/new', values, headers)
.then(function (response) {
console.log(response);
alert("Your submit was successful");
//dispatch(reset('wizard'));
}).catch(function (error) {
console.log(error.response);
alert(error.response.statusText);
});
});
This GET request works everytime, BTW:
getHouses = (e) => {
let token = localStorage.getItem('idToken') || null;
const AuthStr = 'Bearer '.concat(token);
axios.get(BASE_URL + 'household/list', { headers: { Authorization: AuthStr } }).then((response) =>
{
let myData = response.data;
let list = [];
let key =[];
for (let i = 0; i < myData._embedded.length; i++) {
let embedded = myData._embedded[i];
list.push(embedded.friendlyName);
key.push(embedded.id);
}
this.setState({data: list, key: key});
})
.catch((error) => {
console.log('error' + error);
});
}
I'm at my wit's end! Please help!
The localStorage.setItem() is a asynchronous task, and sometimes you run let token = localStorage.getItem('idToken') just after the setItem will fail, so you get a null, so please put the getItem operation some later, have a try, it will be different :
setTimeout(function() {
let token = localStorage.getItem('idToken');
dispatch(receiveLogin(user));
}, 50);
Move your token logic (i.e. localStorage.getItem('idToken');) inside the exported function and it should work
export default (async function showResults(values, dispatch) {
let token = localStorage.getItem('idToken');
const AuthStr = 'Bearer '.concat(token);
let headers ={
headers: { 'Content-Type':'application/json','Authorization' : AuthStr
}
};
axios.post(BASE_URL + 'human/new', values, headers)...
There can't be a case where you set a key value in localstorage and then it returns you null, immediately in the next line.
localStorage.setItem('idToken', user.token);
let token = localStorage.getItem('idToken');
This will only happen if your user.token value is null.
Maybe the case here is your thennable function not returning value to your next then like this:
....
.then(response =>
// return response to your next then function
// this will be passed to next then function as params
return response.json();
).then(({ user, response }) => {
....
Make a function whose return the value or a default value
const [hideTyC, setHideTyC] = useState(false);
const loadTyCFlag = (): any => {
if (
localStorage.getItem("tyc") !== null ||
localStorage.getItem("tyc") !== undefined
) {
return localStorage.getItem("tyc") || false;
}
};
useIonViewDidEnter(() => {
hideTabBar();
setHideTyC(loadTyCFlag());
});

Categories

Resources