Uncontrolled 🔽
In the example, each accordion has its own state(isOpen
). By default, it is set to false
. On click, it flips the value of the state variable(isOpen
) to true or false
. Based on the isOpen
value, it expands and collapses.
Since it controls its own state and doesn't rely on its parents, the children are uncontrolled components.
👉🏽 App.js
const AccordionSection = ({ title, children }) => {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>{title}</button>
<span>{isOpen && children}</span>
</div>
);
};
const UncontrolledAccordion = () => {
return (
<div>
<AccordionSection title="Button 1">Content 1</AccordionSection>
<AccordionSection title="Button 2">Content 2</AccordionSection>
<AccordionSection title="Button 3">Content 3</AccordionSection>
</div>
);
};
export default UncontrolledAccordion;
Controlled ⬇️
Unlike an uncontrolled component, if the parent controls the child's state heavily or the child relies on his parent, that child is a Controlled component.
In the example below, we removed the accordion's ability to control itself and gave that power to the parent. Let's inspect the code.
- Render the accordions without functionality.
- Create state variable
activeIndex
with valuenull
Whenever any accordion gets clicked, the
onClick
function is invoked, andactiveIndex
is set to the currentindex
.By then, re-render happens. And this props
isActive={activeIndex === index}
validate and sendTrue
in props.The accordion that gets clicked will get a
True
boolean value and will be expanded.
Even in the preview of our code, we can see that the parent's state changes every time a child clicks. The parent is controlling the child via props.
👉🏽 App.js
const AccordionSection = ({ title, children, isActive, onClick }) => {
return (
<div>
<button onClick={onClick}>{title}</button>
{isActive && <span>{children}</span>}
</div>
);
};
const ControlledAccordion = () => {
const [activeIndex, setActiveIndex] = useState(null);
return (
<>
{["Content 1", "Content 2", "Content 3"].map((content, index) => (
<AccordionSection
key={index}
title={`Button ${index + 1}`}
isActive={activeIndex === index}
onClick={() => setActiveIndex(activeIndex === index ? null : index)}
>
{content}
</AccordionSection>
))}
</>
);
};
export default ControlledAccordion;
NB: In case anyone is wondering how I got this developer view, it's actually a Chrome extension called React Developer Tools, available in the extension store.