Reputation: 53
In the Section 1 div, if it is active the content will be displayed, otherwise not. The problem in the Section 2 div, when I click on it it shows active but it doesn't display the content.
File App.js
const App = () => {
return (
<div>
<Accordition title={`Section 1`}>
<p>
Lorem ipsum 1 dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat.
</p>
</Accordition>
<Accordition title={`Section 2`}>
<p>
Lorem ipsum 2 dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat.
</p>
</Accordition>
</div>
);
};
export default App;
File components/Accordition.js
const Accordition = ({ title, children }) => {
const [isActive, setisActive] = useState(false);
const toggleCollapseContent = () => {
setisActive(!isActive);
};
useEffect(() => {
let panelContent = document.querySelector(".content");
window.addEventListener("resize", function () {
if (isActive) {
panelContent.style.maxHeight = panelContent.scrollHeight + "px";
} else {
panelContent.style.maxHeight = null;
}
});
}, [isActive]);
useEffect(() => {
let panelContent = document.querySelector(".content");
return () =>
window.removeEventListener("resize", function () {
if (isActive) {
panelContent.style.maxHeight = panelContent.scrollHeight + "px";
} else {
panelContent.style.maxHeight = null;
}
});
});
useEffect(() => {
let panelContent = document.querySelector(".content");
if (isActive) {
panelContent.style.maxHeight = panelContent.scrollHeight + "px";
} else {
panelContent.style.maxHeight = null;
}
});
return (
<div className="lp-collapsible-content">
<div
className={`title ${isActive ? "active" : ""}`}
onClick={toggleCollapseContent}
>
{title}
</div>
<div className="content">{children}</div>
</div>
);
};
export default Accordition;
Or see: https://codesandbox.io/s/demoaccordion-otkoo
Thank you everyone
Upvotes: 1
Views: 94
Reputation: 210
First, check your two useEffect without dependency list, this cause performance issue.
Second, you can just render the content conditionaly to avoid to manipulate style.maxHeight, etc.
{isActive && <div className="content">{children}</div>}
your animation will work fine if there is.
document.querySelector(".content");
the querySelector is global and return the first node found with class '.content' in your case, and may be that is why the second is not shown when active.
Upvotes: 1
Reputation: 56
You have to provide an id for each <Accordition>
component:
<Accordition title={`Section 1`} id='section-1'>
And in Accordition.js use getElementById:
import React, { useEffect, useState } from "react";
const Accordition = ({ title, children, id }) => {
const [isActive, setisActive] = useState(false);
const toggleCollapseContent = () => {
setisActive(!isActive);
};
useEffect(() => {
let panelContent = document.getElementById(id);
window.addEventListener("resize", function () {
if (isActive) {
panelContent.style.maxHeight = panelContent.scrollHeight + "px";
} else {
panelContent.style.maxHeight = null;
}
});
}, [isActive,id]);
useEffect(() => {
let panelContent = document.getElementById(id);
return () =>
window.removeEventListener("resize", function () {
if (isActive) {
panelContent.style.maxHeight = panelContent.scrollHeight + "px";
} else {
panelContent.style.maxHeight = null;
}
});
});
useEffect(() => {
let panelContent = document.getElementById(id);
if (isActive) {
panelContent.style.maxHeight = panelContent.scrollHeight + "px";
} else {
panelContent.style.maxHeight = null;
}
});
return (
<div className="lp-collapsible-content">
<div
className={`title ${isActive ? "active" : ""}`}
onClick={toggleCollapseContent}
>
{title}
</div>
<div className="content" id={id}>{children}</div>
</div>
);
};
export default Accordition;
Enjoy
Upvotes: 0
Reputation: 2412
You need to specify an id
on every Accordion item. Otherwise when you retrieve the content section like this: document.querySelector(".content")
it will just retrieve the first div
with content
class and that's always Section 1.
Set a unique id
on every section, pass it as a prop
to Accordion component and set it on <div className="lp-collapsible-content" id={id}>
. Than you will be able to fetch the content of a specific section like this:
document.querySelector(`#${id} .content`)
Here's a refactored version of your example
Upvotes: 1