About Theo's take of not destructuring props
I can't remember in what video exactly, but I heard Theo saying something about using component props without destructuring them. I gave it a go but stumbled on some scenarios where I'm really scratching my head to know how to do properly without destructuring.
Basically it's a matter of default values and prop forwarding
1. Default Values
I know only of "defaultProps", but not only it is deprecated, but also adds another layer of indirection by having to read the code below at another place
2. Prop Forwarding
In the example I gave before, there is a problem: even though I only want to use
testColor
in the p
element, when I use ...props
in the input
element, I'm passing testColor
as well, which throws a warning.
How it would be with destructured props
Also, the React documentation itself only states destructuring as the way to pass default values to components:
https://react.dev/learn/passing-props-to-a-component#specifying-a-default-value-for-a-propPassing Props to a Component – React
The library for web and native user interfaces
7 Replies
which throws a warning.What warning? if you need default values "without destructuring" you can just use code before return like
Thanks for answering! I saw something like this in the example of how default values work from behind the scenes, in the React doc link I sent (the "Pitfall" section), and it's pretty much this, but the issue below persists
Warning: React does not recognize theBasically, this happens becausetestColor
prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercasetestcolor
instead. If you accidentally passed it from a parent component, remove it from the DOM element.
props
has not only the attributes for input
, but the new prop testColor
as well, which is being passed to the <input>
element even though it does nothing in this caseoh i see, yeah in that case destructuring is superior imo and i do it all the time lol
however i believe you can just cast it if you really need to.
<input {...props as React.ComponentPropsWithoutRef<"input">} />
And yeah, youre absolutely correct about why the error happens, casting should bypass this without having to resort to an any type.
you can also separate testColor and the component props with something like
React.FC<{ testColor: string, inputProps: React.ComponentPropsWithoutRef<"input"> }>
then
<input {...props.inputProps} />
which might be the best practice for that case (you can see that pattern all arround ui packages like Material UI)Without the proper context of why he said it, cant really say much but I use prop spreading all the time. 🥳
Hey! Sorry for the late response. So, I was thinking about this, and it may be correct solution indeed. Like, Using the "...rest" approach with destructuring may lead to some confusion on where the props are going when you type them while using the component. The only downside is that you loose the attribute syntax when you want to use those inputProps, but it makes sense. Gonna make an example below to better clarify what I'm saying, and gonna test using this approach for a couple weeks to see how it goes, but thanks for the help!
FWIW shadcn/ui uses this pattern repeatedly. Not saying that doesn’t mean that it still might not be optimal, but spreading props for components like ones you’d see in a UI library is super common.
Would be interesting to hear a reason when/why not to do this though.
Yeah, I'm doing it more as an experiment. I still very much prefer the spreading approach, but I'm gonna try without it and see how it works. Maybe there are some insights that could help with better prop definition in general.
Some things I've been thinking lately are concepts like: "Is it interesting for the user of the component to have to know its inner workings? Or should it act more like a black box?", "What are the advantages of making a closed component vs a component with subcomponents that the user has to 'Lego'-it together", "When to use children prop vs creating another prop with ReactNode type" and "Should primitives be treated differently regarding their type definitions?".
I know a lot of this depends on the use case, but I just want to have a mental model on what to do in each situation (perhaps make a flow chart also?)