I am working on filter component being made with React.JS. A few of those filtering components are embedded in a panel ( div
). The wrapping parts of the panel look like the below:
Initiative <a onClick={() => {this.setState({ showInitiatives: true })}} className="milestone-list-link" href="#initiative">
{this.state.selectedInitiative}
<InitiativeSelector
initiatives={initiatives || {}}
show={this.state.showInitiatives}
selector={
() => {
console.log('called selector state:', this.state)
this.setState({ showInitiatives: false })
}
}
/>
<FilterIcon />
</a>
My <InitiativeSelector />
looks like the below:
const InitiativeSelector = ({initiatives, show, selector}) => {
return (show) ? (
<div className="list-filter">
<div>
<input placeholder="Search..." />
</div>
<ul>
{
Object.values(initiatives).map((initiative, i) => <li onClick={() => {selector()}} key={i}>{initiative.name}</li> )
}
</ul>
</div>
) : null
}
When I run this, my selector
does get called. Hence, I see state printed to the console. However, this.setState({ showInitiatives: false })
does not seem to do anything. My modal does not hide, and the second (etc) time I click on the <li>
, showInitiatives
still set to true
.
This is because click event bubbles up the DOM tree combined with async nature of setState
First li.onClick
fires calling selector
which calls setState({ showInitiatives: false})
Then a.onClick
fires calling setState({ showInitiatives: true })
. You could check it is true say by adding log statement to it.
Now you have 2 pending updates
{ showInitiatives: false}
{ showInitiatives: true}
which when merged is noop.
You need to either stop event propagation inside li.onClick
by calling e.stopPropagation()
or rethink what a.onClick
handler is doing.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.