I have an array of data that will be used to create accordions, I’d like to make it so that only one of them can be expanded at once (i.e, if the user expands accordion #1 and then #2, #1 will un-expand)
I have this code:
const MyAccordion = props => {
const [expanded, setExpanded] = React.useState()
const handleChange = panel => (_, isExpanded) => {setExpanded(isExpanded ? panel : false)}
const classes = styles //?
let accordionInfo = createAccordionInfo(props.propthing);
return (
<Accordion
key={accordionInfo.uid}
onChange={handleChange(accordionInfo.uid)}
expanded={expanded === accordionInfo.uid}
TransitionProps={{unmountOnExit: true}}
className={classes.accordion}
>
<AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls={`${accordionInfo.uid}-content`} id={`${accordionInfo.uid}-header`}>
<Typography>Accordion Summary</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>Accordion Details</Typography>
</AccordionDetails>
</Accordion>
)
}
const MyAccordions = props => {
const [expanded, setExpanded] = React.useState()
const handleChange = panel => (_, isExpanded) => {setExpanded(isExpanded ? panel : false)}
return (
<div className={styles.root}>
{accordions.map(accordion => (
<MyAccordion onChange={handleChange} propthing={accordion} />
))}
</div>
)
}
I’m quite new to React so I suspect I’ve made a mistake with the states. Any help / tips would be appreciated! Thank you
Advertisement
Answer
It looks like you tried putting state and handlers in both the parent MyAccordions and the children MyAccordion components. If you want only one accordion open at-a-time then I suggest placing the state in the parent component so it can manage what is open/expanded. Use the children accordion ids as the basis of determining which should expand.
Parent
const MyAccordions = props => {
const [expanded, setExpanded] = React.useState(null);
const handleChange = id => (_, isExpanded) => {
// if expanded, set id to open/expand, close it otherwise
setExpanded(isExpanded ? id: null);
};
return (
<div className={styles.root}>
{accordions.map(accordion => {
const info = createAccordionInfo(accordion);
return (
<MyAccordion
key={info.uid} // <-- set React key here!!
onChange={handleChange(info.uid)}
expanded={expanded === info.uid}
/>
)
})}
</div>
);
};
Child
const MyAccordion =({ expanded, onChange }) => {
const classes = styles //?
return (
<Accordion
onChange={onChange}
expanded={expanded}
TransitionProps={{unmountOnExit: true}}
className={classes.accordion}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls={`${accordionInfo.uid}-content`}
id={`${accordionInfo.uid}-header`}
>
<Typography>Accordion Summary</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>Accordion Details</Typography>
</AccordionDetails>
</Accordion>
);
};