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.
Top comments (6)
I have a question as to whether controlled or uncontrolled components are better
Suppose you are building an e-commerce app. Initially, it has 1M product-card components in your app. Each product card has a toggle feature that allows some specific things on the card to be toggled or collapsed on click. To achieve that in an uncontrolled component, we need to have at least one state on each card. It turns out that our app is going to have MILLION states! Would it be performant?
Absolutely no. So, in the Controlled Component, there is just one state instead of a million. That state will stay in the parent. Whenever any of the Million products get clicked, we'll just share that state with that specific product card.
@vilan , can I make sense?
Thank you very much for your answer. That's right. But in some nested dynamic form component encapsulation, the parent component manages all form state. In this scenario, is the design complexity of a controlled form component much more difficult than that of an uncontrolled form component?
In my opinion, it won't matter much.
The design complexity of a controlled form component can indeed be more challenging than that of an uncontrolled form component, especially in the context of nested dynamic form components where the parent component manages all form states.
thanksγAttention to you, stay in touch!
@vilan Sure Buddy π₯
Followed you. Share your linkedIn