Reputation: 128
I am trying to loop over nested object in using map on List Component from MUI. When performing click all elements are getting clicked.
This is my class component:
class TablePivot extends React.Component {
constructor(props) {
super(props)
this.state = {
pivotData: [],
firstLevelOpen: false,
secondLevelOpen: false,
thirdLevelOpen: false,
}
handleFirstListClick = () =>{
this.setState({firstLevelOpen:!this.firstLevelOpen})
console.log(this.secondLevelOpen)
}
handleSecondListClick = () =>{
this.setState({secondLevelOpen:!this.secondLevelOpen})
console.log(this.secondLevelOpen)
}
handleThirdListClick = () =>{
this.setState({thirdLevelOpen:!this.thirdLevelOpen})
console.log(this.thirdLevelOpen)
}
render () {
return (
<>
<List>
{Object.entries(this.state.pivotData).map((key, val) =>{
// console.log(key[1])
return (
<ListItemButton onClick = {event => this.handleFirstListClick}>
<ListItemText primary={key[0]} />
{this.state.firstLevelOpen ? <ExpandLess /> : <ExpandMore />}
{Object.entries(key[1]).map((key,index) =>{
return (
<Collapse in={this.state.firstLevelOpen} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItemButton onClick = {this.handleSecondListClick} sx={{ pl: 4 }}>
<ListItemText primary={key[0]} />
{this.state.secondLevelOpen ? <ExpandLess /> : <ExpandMore />}
{Object.entries(key[1]).map((key,index) =>{
<Collapse in={this.state.secondLevelOpen} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItemButton onClick = {this.handleThirdListClick} sx={{ pl: 4 }}>
<ListItemText primary={key[1]} />
{this.state.thirdLevelOpen ? <ExpandLess /> : <ExpandMore />}
{/* {
Object.entries(key[1]).map((key,index) =>{
return (console.log[key])
})
} */}
</ListItemButton>
</List>
</Collapse>
})
}
</ListItemButton>
</List>
</Collapse>
)
})}
</ListItemButton>
)
})}
</List>
<Snackbar anchorOrigin={{ vertical : "top", horizontal : "right" }} open={this.state.alert} autoHideDuration={5000} onClose={() => this.setState({alert : false})}>
<Alert variant="filled" elevation={6} onClose={() => this.setState({alert : false})} severity={this.state.severity}>
{this.state.alertMsg}
</Alert>
</Snackbar>
</>
)
}
I have tried passing index and event inside onclick like this:
handleFirstListClick(event, index) {
console.log(event.target)
this.setState(
prevState => ({
...prevState.firstLevelOpen,
[index]: !prevState.firstLevelOpen
})
)
console.log(this.state.firstLevelOpen)
// if (this.state.firstLevel === true)
// firstLevel[index] = false
// else
// firstLevel[index] = true
// this.setState({firstLevelOpen:firstLevel});
}
// Changes inside render() inside list component for passing value
<ListItemButton onClick = {event => this.handleFirstListClick(event, val)}>
But doing this will not update state properly. I am not understanding what is going wrong. I am learning react using project. I am struggling for this click event a lot.
Upvotes: 0
Views: 875
Reputation: 715
When you click the first ListItemButton
, it set the firstLevelOpen
state to true
.
And at this part of the code
{this.state.firstLevelOpen ? <ExpandLess /> : <ExpandMore />}
because the firstLevelOpen
is now true
, all the first level ExpandLess
component will be visible.
To handle the state for each button in the list, you can change the state from boolean into object. What you already did is very similar to the code below.
this.state = {
pivotData: [],
firstLevelOpen: {},
secondLevelOpen: {},
thirdLevelOpen: {},
}
on the click handler
handleFirstListClick(event, index) {
this.setState(
prevState => ({
firstLevelOpen: {
...prevState.firstLevelOpen,
[index]: !prevState.firstLevelOpen[index]
}
})
)
}
and now change the conditional rendering to
{this.state.firstLevelOpen[index] ? <ExpandLess /> : <ExpandMore />}
I haven't test it yet, but I guess it should work.
Upvotes: 1