0

I got this code from the Material UI docs on Accordion. I have been studying this code for hours, I can't wrap my head around how it works:

export default function CustomizedAccordions() {
  const [expanded, setExpanded] = React.useState('panel1');

  const handleChange = (panel) => (event, newExpanded) => {
    setExpanded(newExpanded ? panel : false);
  };

  return (
    <div>
      <Accordion square expanded={expanded === 'panel1'} onChange={handleChange('panel1')}>
        <AccordionSummary aria-controls="panel1d-content" id="panel1d-header">
          <Typography>Collapsible Group Item #1</Typography>
        </AccordionSummary>
        <AccordionDetails>
          <Typography>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
            sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing
            elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
          </Typography>
        </AccordionDetails>
      </Accordion>
      <Accordion square expanded={expanded === 'panel2'} onChange={handleChange('panel2')}>
        <AccordionSummary aria-controls="panel2d-content" id="panel2d-header">
          <Typography>Collapsible Group Item #2</Typography>
        </AccordionSummary>
        <AccordionDetails>
          <Typography>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
            sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing
            elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
          </Typography>
        </AccordionDetails>
      </Accordion>
      <Accordion square expanded={expanded === 'panel3'} onChange={handleChange('panel3')}>
        <AccordionSummary aria-controls="panel3d-content" id="panel3d-header">
          <Typography>Collapsible Group Item #3</Typography>
        </AccordionSummary>
        <AccordionDetails>
          <Typography>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
            sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing
            elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
          </Typography>
        </AccordionDetails>
      </Accordion>
    </div>
  );
}

Specifically this line:

const handleChange = (panel) => (event, newExpanded) => {
    setExpanded(newExpanded ? panel : false);
  };

Where is this newExpanded argument coming from? and how is it a Boolean?

Ben
  • 311
  • 4
  • 10
  • 2
    `Accordion` is passing both of those arguments, `event` and `newExpanded`, by calling its `onChange` prop with them. `handleChange` is a _higher-order_ function, it's a _factory_ that creates and returns a change-handling function. – jonrsharpe Aug 17 '21 at 15:34
  • 1
    What it looks like not written as arrow functions `function handleChange(panel){ return function (event, newExpanded) { setExpanded(newExpanded ? panel : false); }}` So when handleChange is called it returns a function. That function is assigned to the click event handler which passes the event object and the state. The `newExpanded` is passed from the accordion component – epascarello Aug 17 '21 at 15:37
  • 1
    `newExpanded` is passed by the `Accordion` component when you trigger the `onChange` event. [See the `onChange` prop of `Accordion`](https://material-ui.com/api/accordion/#props) – 3limin4t0r Aug 17 '21 at 15:39
  • 1
    Without using a curried function (or as you call it, chained arrow function), the component might have looked like [this](https://gist.github.com/3limin4t0r/ec38913d2e6cf421eb0d03c59d850f6c). – 3limin4t0r Aug 17 '21 at 15:47
  • Thanks, I wasn't aware that it was this specific MaterialUI Component which was passing those arguments. – Ben Aug 17 '21 at 15:48

1 Answers1

1

This is an example of closure. You definitely should read about closures more, it is important to understand it well, since it is a common patterns in JS world.

const handleChange = (panel) => (event, newExpanded) => {
    setExpanded(newExpanded ? panel : false);
  };

const newFunction = handleChange('nameOfPanel');

newFunction(someEvent, newExpandedValue);

Check out my example. Notice that calling handleChange returns new function(i named it newFunction ;)). When you call the returned function, you pass these two arguments: event and newExpanded, and then in the body of this function, so this part:

  setExpanded(newExpanded ? panel : false);

the value of panel is remembered from the time I created the newFunction, so panel === 'nameOfPanel'

I know that it might seem to be complicated, but try playing with this pattern a little bit and it will get easier :D