DEV Community

Craig Donavin
Craig Donavin

Posted on

Passing different functions to a reusable component in React

A popular convention in React is to create reusable components based on familiar design elements. These kinds of things can include buttons, switches, text containers, etc.

A Button component may look like this:

const Button = (text, size) => {
  return (
    <div className=`${size}>
      <button>
        {text}
      </button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

You could lose the <div>s if you want. The idea being that it’s written, styled, and may contain some code elements that are reused or adjusted every time. Therefore, you can reuse it a bunch of times, like this:

const App = () => {
  return(
    <div className='button-panel'>
      <Button />
      <Button />
      <Button />
      <Button />
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Now here comes the problem: normally, if I had four buttons, I’d want them each to do something different, right? So without the reusable components in the picture, I would just write four different functions to respond onClick= events.

const App = () => {

  const handleClockIn = () => {
    // some code
  }

  const handleClockOut =() => {
    // some code
  }

  const handleBreakStart =() => {
    // some code
  }

  const handleViewTimeCard =() => {
    // some code
  }
  return(
    <div className='button-panel'>
      <Button txt={'Clock In'} onClick={handleClockIn}/>
      <Button txt={'Clock Out'} onClick={handleClockOut}/>
      <Button txt={'Break Start'} onClick={handleBreakStart}/>
      <Button txt={'View Timecard'} onClick={handleViewTimeCard}/>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

(note: I'm taking some liberties with syntax, as this is not meant to be a working snippet)

However, this won’t work with components. We’ll have to do something different, but first, why doesn’t this work? The reason is that normally in JavaScript, you’d just be assigning an event listener/handler to an element, and then write out what you want to happen when that event occurs. Easy peasey. So why can’t I do it with a component?

It has to do with React’s particular syntax, and when you drop something like this name={object} into the brackets of a component, you’re not assigning an event handler. You’re actually passing a prop to the child component, in which onClick is being passed in as whatever you’re calling the handler function. Soooo, yeah, no wonder it’s not working.

So here’s what you can do instead. First, go ahead and write out your different functions for your buttons. However, instead of assigning an event handler to the child components, you’re going to pass them in as props! That’s right, the first thing you learn (in React)! The reason why you may not have grabbed this idea at first is that examples from React lessons tend to show your parent-child ratio as 1:1, but in front-end coding, it’s very typical to reuse a component or other visual element over and over again. That’s why you have whole design libraries like Bootstrap. In any case, because you can’t write the function into the component (cause otherwise they’re all going to have it), we take care of it “upstairs” and pass it in, like so:

const App = () => {
  const [punch, setPunch] = useState('')

  const handleClockIn = () => {
    let now = new Date()
    setPunch(now.toLocaleTimeString())
  }

  const handleClockOut =() => {
    // some code
  }

  const handleBreakStart =() => {
    // some code
  }

  const handleViewTimeCard =() => {
    // some code
  }
  return(
    <div className='button-panel'>
      <Button text={'Clock In'} handleClick={handleClockIn}/>
      <Button text={'Clock Out'} handleClick={handleClockOut}/>
      <Button text={'Break Start'} handleClick={handleBreakStart}/>
      <Button text={'View Timecard'} handleClick={handleViewTimeCard}/>
    </div>
  )
}

const Button = (text, size, handleClick) => {
  return (
    <div className=`${size}>
      <button onClick={handleClick}>
      {text}
      </button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

(note: Obviously, how you handle your functions is entirely up to you)

This will make it so the Button components are listening for a click and they now have different responses depending on what was passed in to the handleClick prop. Hope this saves you a stackoverflow question!

Top comments (0)