Search code examples
javascriptreactjsreact-hooksonclicknext.js

What's the right way to do `onClick` in a NextJS component?


Doing my project with NextJS I encounter a part where I made a component called app_buttonGray and it looks like this:

// /components/app_buttonGray.js
export default function AppButtonGray({ size, children }){
    return(
        <button className={`flex w-${size ? size : "36"} mt-2 p-1 rounded-md bg-gray-500 hover:bg-gray-800 shadow-lg justify-center`}>
            {children}
        </button>
        
    )
}

Later in my page I want to create multiple buttons but each of them have different purposes So I want to implement onClick like this:

<AppButtonGray size="48" onClick={ () => alert(1)}>New project</AppButtonGray>
<AppButtonGray size="48" onClick={ () => alert(2)}>Open project</AppButtonGray>

But that doesn't seem to work...

After multiple intents I come up with this modification that made it work:

// /components/app_buttonGray.js
export default function AppButtonGray({ size, onClick, children }){
    return(
        <button onClick={onClick} className={`flex w-${size ? size : "36"} mt-2 p-1 rounded-md bg-gray-500 hover:bg-gray-800 shadow-lg justify-center`}>
            {children}
        </button>
        
    )
}

So I had to pass by parameter the onClick and then call it inside the component...

Is that the right way to make this work? If not then what's the right way? Thanks


Solution

  • Yes this is the right way to accomplish what you're trying to do. In React you always have to pass any custom props down to the elements you are returning if you want them to be applied.

    One alternative way to accomplish this however is by using the rest syntax (...) to grab all of the remaining props passed to your component and spreading them onto the child component.

    //                                                      Get the remaining props
    export default function AppButtonGray({ size, children, ...props }) {
      return (
        <button
          className={`flex w-${
            size || "36"
          } mt-2 p-1 rounded-md bg-gray-500 hover:bg-gray-800 shadow-lg justify-center`}
          {...props}
        >
          {children}
        </button>
      );
    }
    

    This is an effective way to pass any props you'd like to your child component but it can be worse for readability when trying to understand the component. This is why some ESLint configs disallow this strategy (you can read more about that here).

    Personally I think you should stick to the way you made it in most cases, you'll thank yourself in the long run when trying to understand the code you wrote.