Doing my project with NextJS I encounter a part where I made a ponent called
app_buttonGray
and it looks like this:
// /ponents/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 e up with this modification that made it work:
// /ponents/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 ponent...
Is that the right way to make this work? If not then what's the right way? Thanks
Doing my project with NextJS I encounter a part where I made a ponent called
app_buttonGray
and it looks like this:
// /ponents/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 e up with this modification that made it work:
// /ponents/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 ponent...
Is that the right way to make this work? If not then what's the right way? Thanks
Share Improve this question asked Jun 30, 2021 at 1:02 RicardoRicardo 1,3562 gold badges11 silver badges22 bronze badges 3- 1 FYI your tailwind dynamic width classname will be removed at build because you can't use string concatenation - here is a more detailed explanation and fix I posted a few days ago - stackoverflow./a/68029107/15304814 – Sean W Commented Jun 30, 2021 at 4:13
-
@SeanW thank you. I learned a lot. I think in my code this is not the case... for what I read in the links you posted I should
not use string concatenation to create class names
, instead I should` Do dynamically select a plete class name` which is my case – Ricardo Commented Jun 30, 2021 at 13:16 -
1
Yes, in your case you could make the "size" the whole tailwind classname instead of just the width number - i.e. lg = "w-36" md = "w-30" etc and in your class className={
${size} flex
}. Lastly, since the size prop is optional you should set your default size in defaultProps to 'w-36'. AppButtonGray.defaultProps = { size: 'w-36' } reactjs/docs/… – Sean W Commented Jun 30, 2021 at 19:39
2 Answers
Reset to default 3Yes this is the right way to acplish 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 acplish this however is by using the rest syntax (...
) to grab all of the remaining props passed to your ponent and spreading them onto the child ponent.
// 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 ponent but it can be worse for readability when trying to understand the ponent. 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.
You can simply use onClick like you used it:
type Props = {
children: React.ReactNode;
onClick?: (e: any) => void;
};
const Button: React.FC<Props> = ({ children, onClick }) => {
return (
<button onClick={onClick}>
{children}
</button>
);
};
export default Button;
Now in your parent, you can simply parse a function. But make sure you use "use client":
"use client"
import Button from "./Button";
<Button onClick={() => {alert("test");}}>Click</Button>