Reputation: 263
I have a parent component that renders a list of children pulled in from an API (which functions correctly). Each child has an option to delete itself. When a child deletes itself, I cannot get the parent to re-render. I have read about 50 answers on here related to this topic and tried all of them and nothing seems to be working. I am missing something and stuck.
The component has redux wired in to it, but I have tried the code with and without redux wired up. I have also tried this.forceUpdate() in the callback, which also does not work (I've commented it out in the example code below).
class Parent extends React.Component {
constructor(props) {
super(props)
this.refresh = this.refresh.bind(this)
this.state = {
refresh: false,
}
}
componentDidMount(){
this.getChildren()
}
refresh = () => {
console.log("State: ", this.state)
this.setState({ refresh: !this.state.refresh })
// this.forceUpdate();
console.log("new state: ", this.state)
}
getChildren = () => {
axios.get(
config.api_url + `/api/children?page=${this.state.page}`,
{headers: {token: ls('token')}
}).then(resp => {
this.setState({
children: this.state.children.concat(resp.data.children)
)}
})
}
render(){
return (
<div>
{_.map(this.state.children, (chidlren,i) =>
<Children
key={i}
children={children}
refresh={() => this.refresh()}
/>
)}
</div>
)
}
}
And then in my Children component, which works perfectly fine, and the delete button successfully deletes the record from the database, I have the following excerpts:
deleteChild = (e) => {
e.preventDefault();
axios.delete(
config.api_url + `/api/children/${this.state.child.id}`,
{headers: {token: ls('token')}}
).then(resp => {
console.log("The response is: ", resp);
})
this.props.refresh();
}
render() {
return(
<button class="btn" onClick={this.deleteChild}>Delete</button>
)}
}
I am sure I am missing something simple or basic, but I can't find it.
Upvotes: 1
Views: 1506
Reputation: 476
Your parent render method depends only on this.state.children which is not changing in your delete event. Either pass in the child id to your this.props.refresh method like this.props.refresh(this.state.child.id) and update this.state.children inside the refresh method or call the get children method again once a delete happens
Code for delete method in child
this.props.refresh(this.state.child.id)
Code for parent refresh method
refresh = (childIdToBeDeleted) => {
console.log("State: ", this.state)
this.setState({ refresh: !this.state.refresh })
// this.forceUpdate();
console.log("new state: ", this.state)
//New code
this.setState({children: this.state.children.filter(child => child.id !== childIdToBeDeleted);
}
Upvotes: 1
Reputation: 3748
Few notes about the code. First removing from db and then reloading might be slow and not the best solution. Maybe consider adding remove()
function which can be passed to the children component to update state more quickly.
Second if you want to call setState
that depends on previous state it is better to use the callback method like this (but i think you need something else see below)
this.setState((prevState,prevProps) =>
{children: prevState.children.concat(resp.data.children)})
Lastly and what i think the issue is. You are not actually calling getChildren
from refresh
method so the state is not updated and if you want gonna reload the whole state from db you shouldn't concat but just set it like this
.then(resp => {
this.setState({children: resp.data.children})
}
Hope it helps.
Edit:
As mentioned in the comments the call to refresh
from children should be in promise then
Upvotes: 0