score:2

What you’re saying not to suggest is in fact the solution I would offer… You’ll need state to control isOpen for the parent component. Also, you should have separate methods in the parent that control state for each accordion, passed along to each accordion in props…

Not sure why you want separate state for the child components. I believe something like this would suffice.

const MasterComponent = () => {
  const [isOpen, setIsOpen] = useState(false);
  const [isOpen1, setIsOpen1] = useState(false);
  const [isOpen2, setIsOpen2] = useState(false);

  const handleParentClose = () => {
    setIsOpen(false);
    setIsOpen1(false);
    setIsOpen2(false);
  }

  return (
    <div>
      <button onClick={handleParentClose}>toggle isOpen parent</button>
      <Accordion isOpen={isOpen1} setIsOpen={setIsOpen1} />
      <Accordion isOpen={isOpen2} setIsOpen={setIsOpen2} />
    </div>
 );
};

const Accordion = props => {
 return (
   <div>
    I'm open: {props.isOpen}
    <button onClick={props.setIsOpen}>toggle isOpen child</button>
   </div>
   );
  }

This doesn't include code for actual visibility toggle, but the state is there, including state that closes accordions on parent close.

score:4

Actually I would say this is way to do it

 const Accordion = ({ isOpen: parentIsOpen = false }) => {
    const [isOpen, setIsOpen] = useState(parentIsOpen);
    const handleSetIsOpen = () => setIsOpen(!isOpen);

    useEffect(() => {
        setIsOpen(parentIsOpen);
    }, [parentIsOpen]);

    return (
      <div>
        I'm open: {isOpen}
        <button onClick={handleSetIsOpen}>toggle isOpen child</button>
      </div>
    );
  };

  const MasterComponent = () => {
    const [isOpen, setIsOpen] = useState(false);
    const handleSetIsOpen = () => setIsOpen(!isOpen);
    return (
      <div>
        <button onClick={handleSetIsOpen}>toggle isOpen parent</button>
        <Accordion isOpen={isOpen} />
        <Accordion isOpen={isOpen} />
      </div>
    );
  };

So just remove state check in a child component, let him update the state but since is updated with the same value it will not rerender or do some expensive behavior.

Tested it today and with a check, if states are different or without is the same, react takes care to not trigger rerender if the state that is updated is the same as before.


Related Query

More Query from same tag