Can I improve performance of a PUT request in React? - javascript

I am using a json-server where I store my database in JSON objects. At some point, I have to update all the values in one of those objects, which is an array. The problem is that when I apply that function that updates the values, the server shuts down. I know that this is happening because I am interacting with the server in a for loop, and I suppose that this is not the best way to do that communication with the server. Here's the code:
The reducer:
import * as ActionTypes from './ActionTypes';
export const Inventario = (state = { errMess: null, inventario: []}, action) => {
switch (action.type) {
case ActionTypes.EDIT_INGREDIENTE:
return {...state, inventario: state.inventario.map((item) => item.id === action.payload.id ?
action.payload : item)};
default:
return state;
}
}
Action Creator:
export const editIngrediente = (ingrediente) => ({
type: ActionTypes.EDIT_INGREDIENTE,
payload: ingrediente
});
export const putIngrediente = (ingredienteId, nombreIngrediente, costo, disponible, conversiones) => (dispatch) => {
const newIngrediente = {
id: ingredienteId,
ingrediente: nombreIngrediente,
costo: costo,
disponible: disponible,
conversiones: conversiones
};
return fetch(baseUrl + 'inventario/' + ingredienteId, {
method: "PUT",
body: JSON.stringify(newIngrediente),
headers: {
"Content-Type": "application/json"
},
credentials: "same-origin"
})
.then(response => {
if (response.ok) {
return response;
} else {
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},
error => {
throw error;
})
.then(response => response.json())
.then(response => {dispatch(editIngrediente(response)); console.log('editado con exito')})
.catch(error => { console.log('put ingrediente', error.message); alert('Your ingredient could not be posted\nError: '+error.message); });
};
And finally where I applied the code:
function restarIngrediente(ingrediente){
for (var elem of ingrediente){
var restar = elem.gramos;
var enInventario = inventario.filter((inven) => inven.ingrediente === elem.ingrediente)[0];
var restante = enInventario.disponible - restar;
putIngrediente(enInventario.id, enInventario.ingrediente, enInventario.costo, restante, enInventario.conversiones);
}
}
Another doubt that I have is that when I want to update the object, I have to pass to the fetch all the attributes of the object, and not only the one that I actually want to change.
If someone can help me, I'd really appreciate it.

Related

react-redux, sometimes working sometimes not when deleting from array

When I delete the order, sometimes the state is updated and sometimes not. It did not work 5 minutes and then started working correctly and I am wondering whether I've messed up something in my code.
action
export const deleteOrder = (token, id) => async dispatch => {
const headers = {
headers: {
Authorization: `Bearer ${token}`,
}
}
const response = await api.delete(`/orders/detail/${id}`, headers)
.catch(error => {
dispatch({ type: constants.PUSH_ERROR, payload: error })
})
if (response && (response.status === 204 || response.status === 301)) {
dispatch({ type: constants.DELETE_ORDER, payload: id });
}
};
reducer
case DELETE_ORDER:
return {
...state,
orders: state.orders.filter(o => o.id !== action.payload)
}
You can ask for more code.

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

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.

I want to declare my variables in one place to not repeat the code, react app

My api fetch calls use the same headers, instead of repeating the variables for each api call function, can I place these variables in one place, then call those variables? I have tried putting them into a function then calling that function, but react complains the variables are missing. I am using a class component and I'm refering to the variables parsed and headersAPI being repeated, I want them in one place, ideally.
componentDidMount() {
this.getUserProfile();
this.searchBands();
}
getUserProfile() {
let parsed = new URLSearchParams(window.location.search).get(
"access_token"
);
parsed = { token: parsed };
console.log(parsed.token);
let headersAPI = {
headers: { Authorization: "Bearer " + parsed.token }
};
fetch(`https://api.spotify.com/v1/me`, headersAPI)
.then(response => response.json())
.then(data =>
this.setState({
userName: data.display_name,
log: console.log(data)
})
)
.catch(error =>
this.setState({
log: console.error("Error:", error),
errorApi: true
})
);
}
searchBands(name) {
let parsed = new URLSearchParams(window.location.search).get(
"access_token"
);
parsed = { token: parsed };
console.log(parsed.token);
let headersAPI = {
headers: { Authorization: "Bearer " + parsed.token }
};
let searchName = this.state.searchName === "" ? "The Cure" : name;
//search band
fetch(
`https://api.spotify.com/v1/search?q=${searchName}&type=artist`,
headersAPI
)
.then(response => response.json())
.then(data =>
this.setState({
artistName: data.artists.items[0],
log: console.log(data),
image: data.artists.items[0].images[0].url
})
)
.catch(error =>
this.setState({
log: console.error("Error:", error),
errorApi: true
})
);
}
I just placed the variables outside the class declaration, then called them inside the api call functions, seemed to work.
const parsed = new URLSearchParams(window.location.search).get("access_token");
const headersAPI = {
headers: { Authorization: "Bearer " + parsed }
};
class App extends Component {..}

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

Promise.all() resolves immediately

I'm trying to take some action after upload completion of multiple images, using Promise.all.
However, the code after then runs before the code being dispatched.
What am I confusing here?
submit_all_images({ dispatch, rootState }) {
const imageFileArray = rootState.imageStore.imageFileArray
var promiseArray = []
for ( var imageFile of imageFileArray ) {
promiseArray.push(dispatch('get_signed_request', imageFile))
}
Promise.all(promiseArray)
.then(results => {
console.log("finished with results: " + results)
return dispatch('submit_entire_form')
});
},
get_signed_request ({ dispatch, commit, state }, imgFile) {
const requestObject = {imageName: imgFile.name, imageType: `${imgFile.type}`}
axios.post('http://localhost:3000/sign-s3', requestObject)
.then(response => {
if (response.body.signedRequest && response.body.awsImageUrl) {
const signedRequest = response.body.signedRequest
const awsImageUrl = response.body.awsImageUrl
dispatch('upload_file', { imgFile, signedRequest, awsImageUrl })
} else {
alert('Could not get signed URL.');
}
}, error => {
console.log("ERROR: " + error)
})
},
upload_file ({ dispatch, commit, state}, { imgFile, signedRequest, awsImageUrl }) {
axios.put(signedRequest, imgFile, {
headers: {'Content-Type': imgFile.type}
}).then(response => {
console.log('finished uploading file: ' + imgFile.name )
commit(types.UPDATE_LICENSE_IMG_URLS, awsImageUrl)
}, error => {
alert("fail")
console.log(error)
})
},
I'm not entirely sure, since I have no experience with vuex, but I guess you're missing a few return statements.
get_signed_request({ dispatch, commit, state }, imgFile){
const requestObject = {imageName: imgFile.name, imageType: `${imgFile.type}`}
//here
return axios.post('http://localhost:3000/sign-s3', requestObject)
.then(response => {
if (response.body.signedRequest && response.body.awsImageUrl) {
const signedRequest = response.body.signedRequest
const awsImageUrl = response.body.awsImageUrl
//here
return dispatch('upload_file', { imgFile, signedRequest, awsImageUrl })
} else {
alert('Could not get signed URL.');
}
}, error => {
console.log("ERROR: " + error)
})
},
upload_file({ dispatch, commit, state}, { imgFile, signedRequest, awsImageUrl }){
//here
return axios.put(signedRequest, imgFile, {
headers: {'Content-Type': imgFile.type}
}).then(response => {
console.log('finished uploading file: ' + imgFile.name )
//and here
return commit(types.UPDATE_LICENSE_IMG_URLS, awsImageUrl)
}, error => {
alert("fail")
console.log(error)
})
},
So that get_signed_request returns a Promise that resolves only after axios.post().then() is done, wich depends on first resolving dispatch('upload_file', ...)
And the same for upload_file depending on resolving axios.put().then()depending on commit(types.UPDATE_LICENSE_IMG_URLS, awsImageUrl)

Categories

Resources