Reload Table After Deleting an Item from It With React

Reload table after deleting an item from it with React

You should put your data in state and then change the state. After changing the state the page automatically re-rendered and changed data of your state will be shown.
So in your delete function simply delete your chosen data and give your remaining data to your state.

Hope this helps, feel free to ask questions if I couldn't explain myself clearly.

How to refresh page after deleting item in React?

I would suggest moving your delete call up to a function in Home that takes an id, and passing that function as a prop to RowCreator.

The state inside the RowCreator is never used and changing it doesn't really help you. What you want is to tell Home that there's been a change and it needs to update its state.

How to update table after delete request in reactjs?

Your delete function need a little rework. When you do the async axios delete call, you'll need to remove the data from your local state too.

handeldelete = async userId => {
await axios.delete("http://localhost:3000/admin/users/" + userId, {
headers: {
'x-access-token': localStorage.getItem("token")
}
});
this.setState((prev) => ({
tableRows: prev.tableRows.filter(
(row) => row.id !== userId
)
}));
};

I reproduce your app with fake data right here : https://codesandbox.io/s/goofy-herschel-vwe2s?file=/src/App.js

React refresh the page after delete button

The [] in the useEffect hook is a dependency array to trigger the effect to run. If you want to trigger the effect (without it going off mercilessly), you can create a new variable that triggers that effect to run.

import React, { useState, useEffect } from "react";
import axios from "axios";
import Table from "../Table/Table";
import "./Display.css";

const Display = () => {
const [state, setState] = useState({ students: [], count: "" });
const [requestData, setRequestData] = useState(new Date());
const [searchItem, setsearchItem] = useState({
item: ""
});

const Search = e => {
setsearchItem({ item: e.target.value });
};

useEffect(() => {
axios
.get("/students")
.then(response => {
setState({
students: response.data.students,
count: response.data.count
});
})
.catch(function(error) {
console.log(error);
});
}, [requestData]);

const nameFilter = state.students.filter(list => {
return list.name.toLowerCase().includes(searchItem.item.toLowerCase());
});

return (
<div>
<h3 align="center">Student tables</h3>
<p align="center">Total students: {state.count}</p>
<div className="input-body">
<div className="row">
<div className="input-field col s6">
<input placeholder="search student" onChange={Search} />
</div>
</div>
</div>
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Date of birth</th>
<th>Address</th>
<th>Zipcode</th>
<th>City</th>
<th>Phone</th>
<th>Email</th>
<th colSpan="2">Action</th>
</tr>
</thead>
{nameFilter.map((object, index) => {
return (
<tbody key={index}>
<Table obj={object} setRequestData={setRequestData} />
</tbody>
);
})}
</table>
</div>
);
};

export default Display;

Then you can trigger it from your Table component:

import React, { useState } from "react";
import { Link } from "react-router-dom";
import axios from "axios";

const Table = props => {
const removeData = () => {
axios
.delete("/students/" + props.obj.id)
.then(() => {
props.setRequestData(new Date());
})
.catch(err => console.log(err));
};

return (
<React.Fragment>
<tr>
<td>{props.obj.name}</td>
<td>{props.obj.birthday}</td>
<td>{props.obj.address}</td>
<td>{props.obj.zipcode}</td>
<td>{props.obj.city}</td>
<td>{props.obj.phone}</td>
<td>{props.obj.email}</td>
<td>
<Link
to={"/edit/" + props.obj.id}
className="waves-effect waves-light btn"
>
Edit
</Link>
</td>
<td>
<button onClick={removeData} className="waves-effect red btn ">
Remove
</button>
</td>
</tr>
</React.Fragment>
);
};

export default Table;

Why do I have to refresh page manually after delete?

What you see in render is what you have in your state.

TL;DR
You need to update your state.


So you have two ways.

  1. Optimistic update, fire delete api to server + setState to delete data in your state. And after you receive response from delete api, act accordingly.

  2. After fire delete api, re-fetch the whole data from server again and update state.

I would suggest option 1 because it feels quicker for user.


Some extra concept here is.

  1. If you want to share state (data) with your "CircuitList" and "CircuitDetail" page. You should store circuits in some parent, like App (or Redux state) and then pass them down to each component.

  2. Again, the optimistic update pattern. Fire API + setState immediately... revert back if things go wrong.

Let me know if you feel like any more help :)


Below is what you can do.

// assuming you have your data in App, state.circuits
class App extends React.Component {
state = {
circuits: [
{ id: 1, title: 'Circuit 1' },
{ id: 2, title: 'Circuit 2' },
{ id: 3, title: 'Circuit 3' },
],
}

afterDeleteCircuit = (circuitID) => {

// state, before delete anything
const currentCircuits = this.state.circuits;

// Remove deleted item from state.
this.setState({
circuits: currentCircuits.filter(circuit => circuit.id !== circuitID),
});

// Fire delete API
axios
.delete(`link-to-api`, this.state)
.then(response => {
if (response.status === 'error') {
// Oops, something went wrong. Let's get that deleted Id back.
this.setState({
circuits: currentCircuits,
});

// Show Error message here.
} else {

// Delete successfully, do nothing.
// Because we already remove the deleted id from state.

// Show success message here.


}
});
}

render() {
return (
<Router>
<Route exact path='/' render={(props) => <CircuitList {...props} circuits={this.state.circuits} /> } />
<Route path='/circuits/:id' render={(props) => <CircuitDetail {...props} onDelete={this.afterDeleteCircuit} /> } />

</Router>
);
}
}


class CircuitList extends React.Component {

render () {
const { circuits } = this.props;
return (
<div>
{circuits.map(circuit => (
<li>{circuit.title} <Link to={`/circuit/${circuit.id}`}>Edit</Link></li>
)}
</div>
);
}
}


class CircuitDetail extends React.Component {

handleDelete = (e) => {
const { match, history } = this.props;
const id = match.params.id;
this.props.onDelete(id);

history.push('/');
}

render () {
return (
<div>
...
// Delete button
<button onClick={this.handleDelete}>Delete</button>
</div>
);
}

}

Update a Table with React Hooks when a Row is Added, Deleted and Modified? [Issue: Gets Before Post and Delete]

Well, you don't what to unconditionally call setData within an useEffect hook with data as a dependency as this will cause an infinite loop (render looping) to occur.

Since the getValues utility already unpacks the response.data value there is likely no need to do it again in your UI. Also, remove the data dependency.

useEffect(() => {
Axios.getValues()
.then((result) => {
setData(result.results);
});
}, []);

For the deleteValues utility, if console.log("Delete Values: ", response); is showing the correct values than I think you need to return this value from deleteValues.

const deleteValues = (id) => {
console.log(id);
const deleteValues = axios
.delete("https://pokeapi.co/api/v2/type/${id}`)
.then((response) => {
console.log("Delete Values: ", response);
return response; // <-- new data values
})
.catch(function (error) {
console.log(error);
});
return deleteValues;
};

Then in ValuesTable you need to update your data state with the new deleted values.

{data.map((values) => {
...
<Button
onClick={() => {
Axios.deleteValues(values.id)
.then(data => setData(data));
}}
/>
...
})};

Update

Ok, since the deleteValues utility doesn't return the updated data from the backend you will need to maintain your local state manually. I suggest doing this work in a callback handler. Upon successful deletion, update the local state.

const [data, setData] = React.useState();

useEffect(() => {
Axios.getValues().then((result) => {
setData(result.data);
});
}, []);

const deleteHandler = id => async () => {
try {
await Axios.deleteValues(id); // no error, assume success
setData(data => data.filter((item) => item.id !== id));
} catch(err) {
// whatever you want to do with error
}
};

return (
...
{data.map((values) => {
<TableRow/>
<TableCell>{values.values}</TableCell>
<TableCell>
<Button onClick={deleteHandler(values.id)}>
Delete
</Button>
})};
...
)

Note that I've written deleteHandler to be a curried function so you don't need an anonymous callback function for the button's onClick handler. It encloses the current id in an "instance" of the callback.

Update 2

If you are making a lot of different changes to your data in the backend it may just be easier to use a "fetch" state trigger to just refetch ("get") your data after each backend update. Anytime you make a call to update data in your DB, upon success trigger the fetch/refetch via a useEffect hook.

const [data, setData] = React.useState();
const [fetchData, setFetchData] = useState(true);

const triggerDataFetch = () => setFetchData(t => !t);

useEffect(() => {
Axios.getValues().then((result) => {
setData(result.data);
});
}, [fetchData]);

const deleteHandler = id => async () => {
try {
await Axios.deleteValues(id); // no error, assume success
triggerDataFetch(); // <-- trigger refetch
} catch(err) {
// whatever you want to do with error
}
};


Related Topics



Leave a reply



Submit