How to make addition of state in react native - javascript

I want to addition of two state,
the both value of state are extracted from json object using a fetch request
constructor(props) {
super(props);
this.state = {
charge:0,
total:0,
};
}
dataFatch()
{
const tot = this.state.total;
fetch('https://xyz.in/app/reg.php', {
method: 'POST',
mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
'item_id':ids,
'func':'item_data',
})
}).then((response) => response.json())
.then((json) => {
this.setState({'total':json.total});
this.setState({'charge':json.charge});
}).catch((err) => { console.log(err); });
}
but after a fetching data charge=30 and total=80
i preform addition like
Let add = this.state.charge+this.state.total;
console.log(add);
but the result is 3080 instead of 110
so how can i solve this problem

It looks like an you are doing concat strings instead of number
I don't see add logic in your api request function but as per you showed you can fix it with below
let add = Number(this.state.charge) + Number(this.state.total);
console.log(add);
But important is you understand that the state you stored isn't number but typeof string.
So while updating state you can make sure it's number not an string so you don't need to convert it into number while doing concat.

Related

How to access a JSON string's values in a React component that have been sent from a server?

I have a React component, Profile, that uses a path variable and props to grab the user id from the path variable, which is then used to send a POST request to the server to retrieve a user's data in the form of a JSON object:
{
"id": 1,
"username": "ss",
"password": "$2a$10$7cN2vQa5VeaAvBNjX5y.0OmVWpH7Rz.sDvuugbMUEtzNJGW63argS",
"name": "Sam",
"email": null,
}
This is then saved to a state variable:
componentDidMount(){
fetch(GET_SINGLE_USER_URL + this.props.match.params.id, {
method: 'GET',
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": localStorage.getItem("token")
},
})
.then(response => response.json())
.then(data => this.setState({user: data}));
}
I want to be able to get the value of the username from the 'user' state using this.state.user within the rest of the componentDidMount() function, so I can use it to send another POST request to get the user's profile image, requiring the username.
When I try:
const imgUrl = USER_IMG_URL + this.state.user[0];
OR
const imgUrl = USER_IMG_URL + this.state.user.username;
within the componentDidMount() function and then try to console.log it only prints the user img url with 'undefined' concatenated:
/image-files/undefined
I could create another controller method in the ImageFileController to handle the id and use that to find the username and then call the same service, but this seems bad practice as I'd have duplicate code?
Also, in the render() method:
render() {
const {user, img, isLoading} = this.state;
console.log(this.props.location);
console.log("USER:");
console.log(user);
}
The user prints fine, so it's definitely been saved to the state.
Edit:
Would this work?
componentDidMount() {
let user = '';
const imgUrl = USER_IMG_URL + user.get("username");
fetch(GET_SINGLE_USER_URL + this.props.match.params.id, {
method: 'GET',
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": localStorage.getItem("token")
},
})
.then(response => response.json())
.then(data => this.setState({user: data}))
.then(data => user += data);
}
Thanks for any help!
In react, setting state is asynchronous. so if you set state in componentDidMount and try to access it in same function, there is no guarantee that you will get value from state. But once state is set and try to get in render method you will get it.
So if you want to get the value and do another call from componentDidMount, use data from server
try something like below
componentDidMount() {
Code to do API call
.then(data => {
this.setState({user: data});
const imgUrl = USER_IMG_URL + data.username;
<use imgUrl>
});
}

Posting data into Firebase - with post request - React

I have some posts into Firebase posts.json file that I have manually entered, that look like below, post1, post2...
When I am entering new data - formData object into Firebase with post request like this:
const submitHandler = e => {
e.preventDefault();
const err = validate();
if(err === false) {
setFormData(formData)
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({formData})
};
fetch('https://blog-d8b04-default-rtdb.europe-west1.firebasedatabase.app/posts.json', requestOptions)
.then(response => setLoading(true))
.then(data => setLoading(false));
}
}
I'm getting post like this, with unique keys as names that is generating firebase, and below formData.
But I want they to be the same format like posts I have entered manually into firebase(posts1, post2).
Is there a way to achieve this?
A JSON literal { formData } is actually shorthand for { formData: formData }, which explains the format you end up with.
You're looking for:
body: JSON.stringify(formData)
So without the {} around formData.

How to update data in ReactJS using JSON server

I am new to react and I can fetch the data from JSON file . Now I need to update those values and submit to the JSON file . I am struggling to submit updated input field in JSON file
submitEmpData(event) {
event.preventDefault();
this.state.empProjects.allocation=this.state.allocation;
this.setState({
empProjects:this.state.empProjects
});
return fetch('http://localhost:3000/Employee/' + this.state.empProjects.id, {
method: 'PUT',
mode: 'CORS',
body: this.state.empProjects,
headers: {
'Content-Type': 'application/json'
}
}).then(res => {
return res;
}).catch(err => err);
}
There are some ways to trigger a render in react:
You send new values down as props to a child component, or
You use a form of state (hooks or setState for example) to update a components state.
In your example, add a setState once the fetch promise has either rejected or resolved, setting the data needed for rendering.
I have restructured the code for better understanding. I believe JSON.stringify() and res.json() may places where you might need to look into.
async submitEmpData(event) {
event.preventDefault();
let { empProjects, allocation } = this.state;
empProjects.allocation = allocation;
// updating the state
this.setState({
empProjects,
});
// calling the api
try {
let res = await fetch("http://localhost:3000/Employee/" + this.state.empProjects.id, {
method: "PUT",
mode: "CORS",
body: JSON.stringify(this.state.empProjects),
headers: {
"Content-Type": "application/json"
}
})
return await res.json();
} catch (err) {
return err;
}
}
Kindly ping me in comments for any clarification
The following method is wrong to change the JSON because the this.state is an object and javascript will check the reference for comparison (See this).
this.state.empProjects.allocation=this.state.allocation;
this.setState({
empProjects:this.state.empProjects
});
instead of this, you can use the spread operator to create a new object:
this.setState({
...this.state, this.state.empProjects: { ...this.state.empProjects, allocation: "NEW value"}
})
Also to send the request using fetch, the body must match with content type:
body: JSON.stringify(this.state.empProjects)

React Hooks setUser & setUserId not updating state despite correct data output

I have a functional component using React hooks. There are quite a few functions that will be running in this component, but one in particular is outputting information correctly but not updating the state as it should.
function StatusDropdown() {
const [user, setUser] = useState('')
const [userId, setUserId] = useState('')
useEffect(() => {
getUser()
}, [])
function getUser() {
return fetch(url, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
}).then(response => response.json())
.then(jsonUser => {
setUser(jsonUser.display_name)
setUserId(jsonUser.id)
console.log(`userInfo: ${jsonUser.id} & ${jsonUser.display_name}`)
//This console log returns proper information: userInfo: 7 & Firstname
})
}
}
I stripped away the unnecessary code, but whenever the user and userId state get used further in my component, the user returns undefined. I use the user state to pass it as an API call query, but because it ends up returning undefined, the API does not properly filter data about a specific user.
I'm just trying to understand if I'm missing something specifically. Any pointers are greatly appreciated!
EDIT:
Below is the subsequent code that relies on the user information above:
function getAuxLog(userId) {
return fetch(`${url}?user=${userId}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
}).then(response => response.json())
.then(auxlogJson => {
setUserAuxLog(auxlogJson)
setLatestAuxLog(auxlogJson.data[auxlogJson.data.length - 1])
setAuxLogLoaded(true)
})
}
The userId is passed to the API url in order to retrieve a log of activity statuses for a specific user. However, with the userId state not being updated, it can not properly retrieve this logged data.

Vuex: Fetch data with axios based on already fetched data

I'm fetching data from an external API via axios in the Vuex store, which gives me an array with objects - let's say - cities.
Each city has a zipCode, which I need to fetch city details with.
I want to add that details-object as a new key to the cities array.
Right now I'm fetching all cities and have another Vuex action to fetch the city details.
ACTION to fetch all cities
fetchCities: ({ commit, state, dispatch }) => {
let baseUrl = "https://my-url/cities";
let config = {
headers: {
accept: "application/json",
Authorization: ...
},
params: {
param1: "a",
param2: "b"
}
};
axios
.get(baseUrl, config)
.then(function(response) {
commit("UPDATE_CITIES_RAW", response.data.items);
})
.catch(function(error) {
console.log(error);
});
dispatch("fetchCityDetails");
},
MUTATION after fetching all cities
UPDATE_CITIES_RAW: (state, payload) => {
state.citiesRaw = payload;
},
Each object in that array has a zipCode, which I'm fetching details about this city with.
I tried to loop the citiesRaw array inside the action to fetch the details and commit a change for each iteration, but the array from the state is empty at this point, because the action gets called before the mutation.
ACTION to fetch city details
fetchCityDetails: ({ commit, state }) => {
let baseUrl = "https://my-url/cities/"
let config = {
headers: {
accept: "application/json",
Authorization: ...
}
};
// citiesRaw is empty at this point
state.citiesRaw.forEach(e => {
let url = baseUrl + e.zipCode;
axios
.get(url, config)
.then(function(response) {
commit("UPDATE_CITY_DETAILS", {
response: response.data,
zipCode: e.zipCode
});
})
.catch(function(error) {
console.log(error);
});
});
},
What are the best ways to wait for the first fetch and then update the array?
Should I even use the same array or create a new one to begin with?
Or is there even a better way to fetch based on fetched data in the Vuex store?
UPDATE
After fixing the dispatching before the async function even finished (thanks, #Y-Gherbi), I also refactored the way of fetching the details:
Component dispatches  fetchCities
in fetchCities action: commit  UPDATE_CITIES
in UPDATE_CITIES mutation: .map on the payload and create new object -> push all to state.cities
in fetchCities action: loop state.cities & dispatch  fetchCityDetails(zipCode) for each city
in fetchCityDetails action: commit  UPDATE_CITY_DETAILS
in UPDATE_CITY_DETAILS mutation: .map on state.cities  and add  cityDetails object  to the referred city object
new actions
fetchCities: ({ commit, state, dispatch }) => {
let baseUrl = "https://my-url/cities";
let config = {
headers: {
accept: "application/json",
Authorization: ...
},
params: {
param1: "a",
param2: "b"
}
};
let url = baseUrl;
axios
.get(url, config)
.then(function(response) {
commit("UPDATE_CITIES", response.data.items);
state.cities.forEach(city => {
dispatch("fetchCityDetails", city.zipCode);
});
}
})
.catch(function(error) {
console.log(error);
});
},
fetchCityDetails: ({ commit }, zipCode) => {
let baseUrl = "https://my-url/cities";
let config = {
headers: {
accept: "application/json",
Authorization: ...
},
};
let url = baseUrl + "/" + zipCode;
axios
.get(url, config)
.then(function(response) {
commit("UPDATE_CITY_DETAILS", {
cityDetails: response.data,
zipCode: zipCode
});
})
.catch(function(error) {
console.log(error);
});
}
new mutations
UPDATE_CITIES: (state, cities) => {
// I don't need all data & I want to rename the keys from the response,
// so I create a new object
cities = cities.map(city => {
let obj = {};
obj.zipCode = city.zip_code
obj.key1 = city.key_1;
obj.key2 = city.key_2;
return obj;
});
state.cities.push(...cities);
},
UPDATE_CITY_DETAILS: (state, payload) => {
let cities = state.cities;
// add one details-object for each city
cities = cities.map(city => {
if (city.zipCode == payload.zipCode) {
city.cityDetails = payload.cityDetails;
}
return city;
});
state.cities = cities;
}
The question remains: Is there a better/more optimized approach to this kind of fetching?
I think that there are much better and elegant ways to deal with this but to simply help you with the bug (looping over an empty array that's expected to be an array of cities)
fix
Try moving the dispatch function to the next line after the commit function. The array (citiesRaw) is empty because you are calling the action before the data is fetched (because axios.get is an async operation)
alternative solution
As you said, the cities are displayed in a table with expandable rows, which are used to display the city details. Fetching 100-1000 cities is quite a lot of data but it's still one call to the back-end. But looping over all these items and doing a request for every one of them could be problematic from a performance and bandwidth (if that's the correct term for large data usage) perspective.
Personally, I would handle each request whenever the user actually needs this data. In your case whenever the user clicked on a row to expand it.
Storing it in the store?
Whenever you want to store the city details in the store is up to you. You could just keep it in the component but personally, I would use it as some kind of cache mechanism.
When the user clicked on a row, check if the details are already fetched
if(!state.cityDetails[key]) {
axios.get()
.then(res => {
// Commit a mutation that saves the fetched details
})
.catch((error) => {
// Handle error
})
} else {
// Use the 'cached' cityDetails
}
Your store could look something like this:
{
cityDetails: {
keyCouldBeIdOrZipcode: {...},
anOtherAlreadyFetchedCity: {...},
}
}
sorry for the typos and bad formatting. Typing code on a phone is horrible

Categories

Resources