Reputation: 15
After checking other posts, I did not find an exact answer to my question but apparently this problem happens to others, just not exactly my problem. Every PUT, POST , DELETE Request sent from the function below is called twice. HERE is my function code that handle user changes(add,update,delete) to the UI. It's part of ReactJS class component:
commitChanges({ added, changed, deleted }) {
this.setState((state) => {
let { data } = state;
if (added) {
const startingAddedId = data!=undefined && data.length > 0 ? data[data.length - 1].id + 1 : 0;
var TBname= decodeURIComponent(window.location.pathname.slice(window.location.pathname.lastIndexOf(':')+1 ));
if ( data == undefined) data = [{ id: startingAddedId, ...added} ];
data = [...data, { id: startingAddedId, ...added }];
fetch('http://localhost:3001/api/appo',
{
method: 'POST',
headers: { 'Accept': 'application/json, text/plain, */*' ,'Content-Type': 'application/json' },
body: JSON.stringify({ id: startingAddedId,"TBname": TBname, ...added } )
})
.then( (response) => this.setState({ data: data }) ) .catch(() => console.log('POST failed'));
this.setState({ data: data })
console.log(this.state.data);
}
if (changed) {
data.map((appointment) => {
console.log(changed[appointment._id]);
if (changed[appointment.id] != undefined) {
//console.log("JSON",JSON.stringify({...appointment,...changed[appointment.id],} ) );
fetch('http://localhost:3001/api/appo/'+appointment.id,
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({...appointment,...changed[appointment.id],} )
}).catch(() => console.log('PUT failed'));
}
});
data = data.map((appointment) =>
changed[appointment.id] ? { ...appointment, ...changed[appointment.id] } : appointment)
this.setState({ data: data });
}
if (deleted !== undefined) {
console.log(deleted);
fetch('http://localhost:3001/api/appo/'+deleted,
{
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
}).catch(() => console.log('DELETE failed'));
data = data.filter(appointment => appointment.id !== deleted);
this.setState({ data: data })
}
return { data };
});
}
For example if I want to send POST Request to create an item this item will be created twice with the same id.
Upvotes: 1
Views: 1257
Reputation: 11
The fetch requests in your code are asynchronous, and maybe invoking setState before these requests have completed. Because of the asynchronous nature of fetch, there's no guarantee that the requests will be finished when you call setState. As a result, you end up making another call to setState within the .then callback of the fetch, which can lead to unexpected behavior or redundant state updates.
try:
commitChanges({ added, changed, deleted }) {
const TBname = decodeURIComponent(window.location.pathname.slice(window.location.pathname.lastIndexOf(':') + 1));
if (added) {
const startingAddedId = this.state.data && this.state.data.length > 0 ? this.state.data[this.state.data.length - 1].id + 1 : 0;
fetch('http://localhost:3001/api/appo', {
method: 'POST',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify({ id: startingAddedId, "TBname": TBname, ...added })
})
.then(response => response.json())
.then(data => {
this.setState((state) => {
const newData = [...state.data, data];
return { data: newData };
});
})
.catch(error => console.log('POST failed:', error));
}
if (changed) {
const updatePromises = Object.keys(changed).map(id => {
return fetch(`http://localhost:3001/api/appo/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ...changed[id] })
})
.then(response => response.json())
});
Promise.all(updatePromises)
.then(updatedData => {
this.setState((state) => {
const newData = state.data.map(appointment => {
const updatedInfo = updatedData.find(item => item.id === appointment.id);
return updatedInfo ? updatedInfo : appointment;
});
return { data: newData };
});
})
.catch(error => console.log('PUT failed:', error));
}
if (deleted !== undefined) {
fetch(`http://localhost:3001/api/appo/${deleted}`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
})
.then(response => {
if (response.ok) {
this.setState((state) => {
const newData = state.data.filter(appointment => appointment.id !== deleted);
return { data: newData };
});
} else {
console.log('DELETE failed:', response.statusText);
}
});
}
}
Upvotes: 0
Reputation: 2132
Don't make any http request inside the setState callback function, its not a good practise and setting a state inside the state callback result this issue.
remove the setState callback and doing something like below will resolve your issue.
commitChanges({ added, changed, deleted }) {
let { data } = state;
if (added) {
const startingAddedId = data!=undefined && data.length > 0 ? data[data.length - 1].id + 1 : 0;
var TBname= decodeURIComponent(window.location.pathname.slice(window.location.pathname.lastIndexOf(':')+1 ));
if ( data == undefined) data = [{ id: startingAddedId, ...added} ];
data = [...data, { id: startingAddedId, ...added }];
fetch('http://localhost:3001/api/appo',
{
method: 'POST',
headers: { 'Accept': 'application/json, text/plain, */*' ,'Content-Type': 'application/json' },
body: JSON.stringify({ id: startingAddedId,"TBname": TBname, ...added } )
})
.then( (response) => this.setState({ data: data }) ) .catch(() => console.log('POST failed'));
this.setState({ data: data })
console.log(this.state.data);
}
if (changed) {
data.map((appointment) => {
console.log(changed[appointment._id]);
if (changed[appointment.id] != undefined) {
//console.log("JSON",JSON.stringify({...appointment,...changed[appointment.id],} ) );
fetch('http://localhost:3001/api/appo/'+appointment.id,
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({...appointment,...changed[appointment.id],} )
}).catch(() => console.log('PUT failed'));
}
});
data = data.map((appointment) =>
changed[appointment.id] ? { ...appointment, ...changed[appointment.id] } : appointment)
this.setState({ data: data });
}
if (deleted !== undefined) {
console.log(deleted);
fetch('http://localhost:3001/api/appo/'+deleted,
{
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
}).catch(() => console.log('DELETE failed'));
data = data.filter(appointment => appointment.id !== deleted);
this.setState({ data: data })
}
}
Upvotes: 1