Reputation: 461
import React, { useState } from 'react';
const Accordion = ({ items }) => {
const [activeIndex, setActiveIndex] = useState(null);
const onTitleClick = (index) => {
setActiveIndex(index);
};
const renderedItems = items.map((item, index) => {
const active = index === activeIndex ? 'active' : '';
return (
<React.Fragment key={item.title}>
<div className={`title ${active}`} onClick={() => onTitleClick(index)}>
<i className='dropdown icon'></i>
{item.title}
</div>
<div className={`content ${active}`}>
<p>{item.content}</p>
</div>
</React.Fragment>
);
});
return <div className='ui styled accordion'>{renderedItems}</div>;
};
export default Accordion;
I created an accordion using Semantic UI library. I was able to set class of dropdown "active" so anything that I click will expand.
I am trying to implement "Close on second click" functionality to the below code, so I try to implement by adding following code under onTitleClick function:
const onTitleClick = (index) => {
if (index === activeIndex) {
setActiveIndex(null); // in case 'clicked index' is the same as what's active, then configure it to "null" and rerender
}
setActiveIndex(index);
};
My understanding is whenever the state updates, react will run its script again, so in this particular situation, that variable "active" should return empty string if clicked for the same Index.
Rather than my expectation, nothing happened when I clicked it for the second time.
I tried to console.log in the if statement and it will show that I have clicked the item for the second time.
Please advise.
Upvotes: 1
Views: 1747
Reputation: 1
I have tried with react class component so worked it.
import React, { Component } from 'react';
class Accordion extends Component {
state = {
activeIndex: null
}
onTitleClick = (index) => event => {
const { activeIndex } = this.state;
this.setState({ activeIndex: activeIndex == index ? null : index })
};
render() {
const { activeIndex } = this.state;
const{items}=this.props;
return <div className='ui styled accordion'>
{
items.map((item, index) => {
const active = index === activeIndex ? 'active' : '';
return <React.Fragment key={item.title}>
<div className={`title ${active}`} onClick={this.onTitleClick(index)}>
<i className='dropdown icon'></i>
{item.title}
</div>
<div className={`content ${active}`}>
<p>{item.content}</p>
</div>
</React.Fragment>
})
}
</div>
}
}
export default Accordion;
Upvotes: 0
Reputation: 6736
Try the below approach,
const onTitleClick = (index) => {
setActiveIndex(activeIndex !== index ? index : null);
};
Upvotes: 0
Reputation: 5054
The issue is here:
const onTitleClick = (index) => {
if (index === activeIndex) {
setActiveIndex(null); // in case 'clicked index' is the same as what's active, then configure it to "null" and rerender
}
setActiveIndex(index); <-- here
}
what happening here is if if
condition matches then it sets to setActiveIndex
null but code will run so again it sets to setActiveIndex(index)
. That's why click is not working . You need to do this:
const onTitleClick = (index) => {
if (activeIndex === index) {
setActiveIndex(null);
} else {
setActiveIndex(index);
}
};
Here is the demo: https://codesandbox.io/s/musing-poitras-bkiwh?file=/src/App.js:270-418
Upvotes: 3