challenges

React Components: Part 3

Workshop context

Before this workshop

  • Last workshop, we defined props and types for the Button and Card components.

This workshop

  • In this workshop, we’re going to delegate props that aren’t explicitly destructured.

After this workshop

  • In future workshops, we’ll handle styling of the Button and Card components, and animations for the Spinner component.

Workshop goal

By the end of this workshop:

  1. Consumers of the Button component will be able to pass arbitrary button props to the component and the props will be used in the returned button element.
    • For example, <Button type="submit" onClick={handleClick}>Submit</Button> will return a button element that has type="submit" and onClick={handleClick}.
  2. Similarly, consumers of the Card component will be able to pass arbitrary article props to the component and the props will be used in the returned article element.
  3. Both the className defined within the component and any incoming className values will be included in the rendered component.
    • For example, the output of <Button className="button-class">Press me!</Button> will include both button-class and the {styles.wrapper} class defined within the component.
    • Note: clsx has been installed and is available for use in this app.

Hints

Hint 1 To collect all the props that aren’t explicitly destructured, use this syntax (as described by MDN ):

const { textColor, backgroundColor, children, ...delegated } = props;

...delegated is not a special name; you can use whatever variable name you wish instead (for example, ...theRestOfTheProps). However, ...delegated is conventional because these props are being “delegated” from the component to its top level element.

Hint 2 To spread the props in the returned element, use this syntax:

Card.tsx

function Card({
  textColor,
  backgroundColor,
  children,
  ...delegated
}: CardProps) {
  return (
    <article 
      className={styles.wrapper} 
      {...delegated}>
    {children}
    </article>
  );
}    

Hint 3 To combine the incoming className value with the existing value within the component, first the className prop will need to be destructured. Then, combine the value with the existing className value using clsx:

Card.tsx

function Card({
  textColor,
  backgroundColor,
  className,
  children,
  ...delegated
}: CardProps) {
  return (
    <article 
      className={clsx(styles.wrapper, className)}
      {...delegated}>
      {children}
    </article>
  );
}    

Resources