Most React devs don’t understand generic components

  Рет қаралды 48,564

Matt Pocock

Matt Pocock

Күн бұрын

Пікірлер: 109
@helleye311
@helleye311 8 ай бұрын
Absolutely love generic components. It's so nice to get all the highlighting. I usually extend {id: string}, this way I can add a key for mapping based on the id, and in most cases I have id in all the objects I'm displaying anyway. Another cool use case is a custom dropdown that takes a list of objects. Then you can also have a custom typesafe onChange. Also works great in combination with discriminated union props, if you pass 'multiple' prop your onChange is (value:T[])=>void, if you don't it's value:(T | undefined)=>void. It does get a little messy with so much functionality packed into one component (I also had a dropdown that would make a fetch call for data to populate it, which of course also was returning T[] for type safety), but I'm sure there's a way to make it more concise with some custom hooks and separate components.
@QwDragon
@QwDragon 8 ай бұрын
Completely agree!
@SpaghettiRealm
@SpaghettiRealm 8 ай бұрын
You can also extends object wich in js everything is object 😂
@JohnBuildWebsites
@JohnBuildWebsites 8 ай бұрын
THANK YOU! Was having that exact error when spreading a field object for a form today. Will try adding Extends Record to the type first thing tomorrow!
@JeyPeyy
@JeyPeyy 8 ай бұрын
Great video! The only change I'd make is to use unknown instead of any in TRow extends Record
@mattpocockuk
@mattpocockuk 8 ай бұрын
In this case because we REALLY can pass anything into that Record, it doesn't matter which one you pick.
@foolmoron
@foolmoron 8 ай бұрын
@@mattpocockuk I think the better answer here is that `any` is perfectly good to use in a generic type constraints, since the `any` is never used by an actual instance of a variable, it's just a constraint. If you were typing an actual obj variable whole values could be anything, you should really use Record, so that TS can encourage you to do the appropriate type narrowing or casting on the values that you get from that obj.
@barneylaurance1865
@barneylaurance1865 8 ай бұрын
@@mattpocockuk I'd think if they both work equally well then unknown is preferable. I avoid any as much as I can, I think of it as just a last resort escape-hatch for when you don't want or can't deal with static typing. It's weird blend of type type and bottom type at the same time.
@mattpocockuk
@mattpocockuk 8 ай бұрын
@@barneylaurance1865OK - but that rule of thumb doesn't make sense in a context where you want the widest type possible. In that case, either are fine.
@JulianColeman03
@JulianColeman03 8 ай бұрын
I think more impressive than the explanation of generics was how you produced that intro zoom out effect by adjusting the focal length. Amazing
@krauterfrischkase8939
@krauterfrischkase8939 8 ай бұрын
Wouldn't it be "more react" to render the list of rows outside the Table component and then insert that into the Table children? React's philosophy emphasizes composition over configuration which would make the Table component versatile and more flexible.
@proosee
@proosee 8 ай бұрын
I'm not an expert, but I don't think it is crime to have one component with two renderers instead of two components, especially if they never will be used separately, because how you want to use row without table?
@mattpocockuk
@mattpocockuk 8 ай бұрын
No, both ways are equally "React"
@ra2enjoyer708
@ra2enjoyer708 8 ай бұрын
It depends on the usecase. Especially in cases of tables, which have fixed structure declared by headers and can be expressed as 2D arrays easily, consuming JS types instead of opaque React components allows to wrap the results in row components with consistent styling. Versatility of children has a price on its parent in the form of forcing it to support a union of all children options. I.e. something like linebreaks for too long values in a column are trivially to compute from a string, which has a known length, while font size and all paddings are known to the table component, since these values are controlled by it in the first place. Interacting with them as components however devolves into hacks around React API and DOM-related boilerplate for counting pixels (good luck dealing with off-by-one errors caused by rounding errors).
@QwDragon
@QwDragon 8 ай бұрын
It's a simplified example. If he would've shown you smth real it would've take several hours to explain.
@Netherlands031
@Netherlands031 8 ай бұрын
Yeah but then the table can't for example do pagination, where the table keeps track of the page, slices the list of data and then only rendere that data with the render function
@ColinRichardson
@ColinRichardson 8 ай бұрын
Such a Generic title
@mycodingtutorials
@mycodingtutorials 8 ай бұрын
What font is this? What theme and what IDE?
@QwDragon
@QwDragon 8 ай бұрын
A very big problem with final code: using lambda fuction as a component will force recriating of everything it renders every time and will make completely impossible to keep any state anywhere inside. One more issue: no keys are specified on rows.
@pavloomelianchuk
@pavloomelianchuk 8 ай бұрын
Looks like another try for me, to understand "generics" in react. Eventually it will come 😜 Thanks!
@tomasburian6550
@tomasburian6550 7 ай бұрын
Learned generics quite recently and love them. Great videos here, Matt. Subscribed for life.
@thepetesmith
@thepetesmith 8 ай бұрын
I’m confused a bit because I always use React.FC and pass a props Type as the type arg. I don’t get how in your example you aren’t passing the type, but the generic infers the type by argument order? I’ve seen how you can pass a type argument in the jsx with angle brackets
@Rebel101
@Rebel101 7 ай бұрын
Hey Matt, question: See when you hover over react component jsx call, it just references type names instead of actual types like it does when you call is a a function. Is it possible to write a genetic type for ReactNode that solves this issue?
@LetalisLatrodectus
@LetalisLatrodectus 2 ай бұрын
Why use any in the Record instead of unknown?
@dmytroprokoptsov9587
@dmytroprokoptsov9587 8 ай бұрын
Hi, Matt) Your videos as beautiful as your accent! But I'm here to ask you and your community a question: is there a way in TypeScript I can check on type level whether object has keys or not? I know it is possible with Arrays, but with objects seems to be not
@billyfigueroa1617
@billyfigueroa1617 7 ай бұрын
Matt your videos are amazing. I have learned a lot from you I do have a question. Is it possible to use different types for a generic component? for example, I have a carousel I want to create and I want it to be able to display different things. Like it can display an image and become a slider in a sense or it can just be a scrollable like hero section. Is it possible to have something like Carousel and Coraosel where Image and Info are objects that do not have the same attributes. Something like Image has name, urlImg and Info has header, subheader, content
@CodeZakk
@CodeZakk 8 ай бұрын
Yeah to the point and concise tutorial.my question is can we object and array on the extends and also is Record a typescript feature?🎉🎉
@dennisgonzales9521
@dennisgonzales9521 7 ай бұрын
2:38 addding a comma here throws me off, that why I prefer to use the classic function declaration for my components instead of arrow functions.
@engine_man
@engine_man 8 ай бұрын
Dropping gems as usual. I never understood with that Intrinsic attributes thing meant.
@ctpaintball4life
@ctpaintball4life 8 ай бұрын
Slotted components are really hot right now. Is it possible to do this type of inference with JSX?
@Shyam_Mahanta
@Shyam_Mahanta 8 ай бұрын
Where to buy typescript book you have behind?
@Clem.E
@Clem.E 7 ай бұрын
React Table nightmare now explained, thanks!
@leftis95
@leftis95 8 ай бұрын
How come the comma "," solved the .tsx errors inside the generic type?
@Pete133
@Pete133 8 ай бұрын
Yes I would like to know why the comma makes a difference as well. Is it just a random buggy thing about typescript or are we missing something fundamental? *Edit* Ok so Matt says @2:40 that adding the comma lets typescript know that is a type parameter, but I didn't understand what else it would be other than a type parameter. Because we're using a const variables, which in a react app can be directly assigned to JSX... like const foo = ... typescript doesn't know that we're not trying to assign JSX. So adding a comma there lets typescript know we're using a type parameter rather than JSX.
@andriiv7033
@andriiv7033 8 ай бұрын
Great. The only thing is that the any should be replaced with a generic type too, shouldn’t it?
@versaleyoutubevanced8647
@versaleyoutubevanced8647 8 ай бұрын
do you have any thoughts on the fact we can't type children? ReactNode is more like Record for JSX I'm talking about complex children demanding like 3 childs, , and . Or restrict children to have only one child with data atribute 'foo'...
@PickleRiiiiiiick
@PickleRiiiiiiick 7 ай бұрын
You're the best dude. And I follow you on everything.
@Krzysiekoy
@Krzysiekoy 8 ай бұрын
How does typescript "decide" which prop to use for the type inference for the type argument T? Take this example: const Table = ({rows, randomProp}: {rows: T[], randomProp: T}) => { return rows } Table({rows: [1,2,3], randomProp: "foobar"}) This will error out saying "Type 'string' is not assignable to type 'number'." Okay, why does rows prop take precedence? Why doesn't this error the other way around, i.e. "Type 'number []' is not assignable to type string [ ]". What makes the "rows" component "win" when it comes to type inference?
@the_blue_flash
@the_blue_flash 8 ай бұрын
Have you tried switching rows and randomProp when calling the function? I think that's where it's inferencing. Another way would be specifying it (e.g. Table(/*args*/) )
@Krzysiekoy
@Krzysiekoy 8 ай бұрын
@@the_blue_flash Yes, I've tried switching the props around and it makes no difference.
@vytah
@vytah 8 ай бұрын
It doesn't matter except for the way the error message is formatted.
@mattpocockuk
@mattpocockuk 8 ай бұрын
Fabulous question. In your example, there is no true way to figure out which one goes first. So TypeScript picks one - I'm sure the compiler knows which, but I don't have an intuition for it. To customize which one gets selected, you can use NoInfer from ts-toolbelt. NoInfer will be coming to TypeScript in 5.4.
@Krzysiekoy
@Krzysiekoy 8 ай бұрын
@@mattpocockuk Thanks Matt! Appreciate your answer.
@iamandrewluca
@iamandrewluca 8 ай бұрын
Another subjective opinion is using instead of props.renderRow(row) The former version allows to call hooks inside of it, but it looks strange. The benefit of the former is that you can pass a component renderRow={MyRowComponent} but you lose type inference. I suppose the latter is the right way of rendering the row in this case props.renderRow(row) Btw, great video as usual, short and on point!
@leotravel85
@leotravel85 8 ай бұрын
Record whould have been better
@QwDragon
@QwDragon 8 ай бұрын
No. Always use any instead of unknown in generic constraints.
@leotravel85
@leotravel85 8 ай бұрын
@@QwDragonWhy?
@fow7139
@fow7139 8 ай бұрын
@@QwDragon No, you should not. Any is not restricted and can be considered as a bad practice. In critical environments, it actually is. In those cases, you want to make another component from Table that will correctly wraps the type or pass it as a generic :
@sludgepuppy
@sludgepuppy 8 ай бұрын
Thank you, really nice and clear and simple 👍
@DmitriiBaranov-ib3kf
@DmitriiBaranov-ib3kf 8 ай бұрын
I prefer going with Record. And Vue 😅
@syedhaider0916
@syedhaider0916 6 ай бұрын
Probably the best generic video ever.
@JaffyMaglinte
@JaffyMaglinte 8 ай бұрын
Nice! Got it now
@henrym5034
@henrym5034 8 ай бұрын
Concise and to the point 👍🏼
@hakuna_matata_hakuna
@hakuna_matata_hakuna 8 ай бұрын
can ytou do a video on extends , it seems like a super power
@glorrin
@glorrin 8 ай бұрын
I have this problem in typescript I encounter from time to time, and no clue how to type it. function assignValue(myObject: TObject, key: TKey, value: Tvalue){...} TObject is usualy easy enough to type Tkey, is just keyof TObject But I have no clue how to get Tvalue to be typeof myObject[key]
@laminecherif7724
@laminecherif7724 8 ай бұрын
function assignValue(myObject:TObject, key:TKey, value :TObject[TKey]) {....}
@gerhardsteenkamp562
@gerhardsteenkamp562 8 ай бұрын
The confusing bit for me was that it doesn’t work the way generics usually work, in that you don’t pass a type argument to the component, but instead the generic acts as a placeholder to infer the type of regular props that are passed to the component. And then you can use that inferred type in multiple places in the component.
@MaPhongBa129
@MaPhongBa129 8 ай бұрын
Put a comma after type param is magic, most of the time, I change function from arrow to normal function.
@pedrohenriquepires9484
@pedrohenriquepires9484 8 ай бұрын
Wonderful content, as always! I wrote a small article on about this some time ago, inspired by your content about generics. Thank you for your amazing work!
@orcdev
@orcdev 8 ай бұрын
But what about my eslint rule "no any" 😅
@buggycoder7900
@buggycoder7900 8 ай бұрын
can't we have ??
@yah3136
@yah3136 8 ай бұрын
I will just ignore this video and ask youtube to not show it again just for this nice presumptuous title ... well done Mr "better than most devs" ...
@mattpocockuk
@mattpocockuk 8 ай бұрын
It's just a shorthand for 'advanced content'.
@andrewpleshko365
@andrewpleshko365 8 ай бұрын
Great! Thank you
@boris_raduloff
@boris_raduloff 8 ай бұрын
This is quite similar to lifetime annotations in rust but about types instead of memory freeing.
@mrlectus
@mrlectus 8 ай бұрын
no
@boris_raduloff
@boris_raduloff 8 ай бұрын
@@mrlectus extremely insightful
@macon5696
@macon5696 8 ай бұрын
some time ago, i've managed the same problem, but i did't find solution to do the same with memo without TS issues
@TeaBroski
@TeaBroski 8 ай бұрын
Wow, the knowledge this man ...spreads is always mind blowing
@joshmarom
@joshmarom 8 ай бұрын
That was great thanks
@ninjarogue
@ninjarogue 8 ай бұрын
Excellent!
@Wielorybkek
@Wielorybkek 8 ай бұрын
can't it be a footgun? whenever I see hacks like this I think that such use case was not considered by framework authors and they might not support it. it might stop working at some point or have bugs later along the way.
@mattpocockuk
@mattpocockuk 8 ай бұрын
No, it's not a footgun. It's an extremely common pattern used in tons of different libraries.
@KoenVerheyen
@KoenVerheyen 8 ай бұрын
Don't need to add a key-attribute in this case?
@DemanaJaire
@DemanaJaire 8 ай бұрын
Still needed
@QwDragon
@QwDragon 8 ай бұрын
Yes, but that does nothing while he uses lambda function as a component...
@GilEpshtain
@GilEpshtain 8 ай бұрын
the only downside is that you have to use the syntax "const C = (..." and cant write "const C: React.FC = ..."
@akosbalint3485
@akosbalint3485 8 ай бұрын
Do somebody know how to add forwardRef to generic components?
@mattpocockuk
@mattpocockuk 8 ай бұрын
github.com/total-typescript/react-typescript-tutorial/blob/main/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx
@akosbalint3485
@akosbalint3485 8 ай бұрын
@@mattpocockuk Thank you Matt!
@MerthanMerter
@MerthanMerter 8 ай бұрын
amazing
@michamazurkiewicz80
@michamazurkiewicz80 5 ай бұрын
Speaking from experience this is really bad to show to people. XD I have an app with 10 or more tables and initially someone had idea why not just making single table for all of them... But it doesnt really make sense cause each of these tables is different... has different actions, items, filters...etc... that we ended up with a monster that tides our entire application. Whenever you make change you have to go over entire app to check if everything is working etc. Lesson learned.. just copy the code and have 2 tables or 10 tables that are all simple and clean. Have logic only interesting for them and you dont have to worry to break entire app when making change in single table. So in this situation big no to generics.
@khoihoang8888
@khoihoang8888 8 ай бұрын
love it!
@iMakeYoutubeConfused
@iMakeYoutubeConfused 8 ай бұрын
The only time I'm not guilty of
@Hugos68
@Hugos68 8 ай бұрын
Congrats on becoming a father!
@lifeiscontent
@lifeiscontent 8 ай бұрын
Fix forwardRef so these kinds of components aren’t a nightmare to build
@saidabedi2836
@saidabedi2836 8 ай бұрын
🔥
@1felixxex1
@1felixxex1 8 ай бұрын
nice
@paxdriver
@paxdriver 8 ай бұрын
I still don't understand the benefit of typescript. This is way more mental load than writing a proper function with guardrails. How is this easier than vanilla js?
@Netherlands031
@Netherlands031 8 ай бұрын
Because typescript will now error in the renderrow function if you try to access a row property that doesn't exist. And you get autocomplete if you do 'row.' inside of renderrow. So a much improved DX for the cost of just a few lines of code. The mental load is pretty small if you have some practice with this stuff
@deniyii
@deniyii 8 ай бұрын
It’s not supposed to be easier. It’s always going to be easier to write untyped spaghetti than any typed language.
@awekeningbro1207
@awekeningbro1207 7 ай бұрын
js is waking on sahara desert, ts is walking on a well built road on sahara
@paxdriver
@paxdriver 7 ай бұрын
@@Netherlands031 maybe i'll figure it out one day, just started with it this year and i've been writing js for over 20 yrs so it's probably a stubborn bias of mine, i'll admit. i'm trying to see it, though
@paxdriver
@paxdriver 7 ай бұрын
@@deniyii you can type javascript yourself if you write functions for it. that's my whole point. instead of focusing on all this new syntax and stuff it's cleaner code and easier to write when you yourself wrote the typechecking function. const kind of solved this for anyone who puts in a few minutes to write little type checking functions imho.
@fabius-maximus
@fabius-maximus 8 ай бұрын
Ugh vue does this way cleaner
@kirylbehansky1315
@kirylbehansky1315 8 ай бұрын
Only react devs can’t understand that 😢
@badwolf9090
@badwolf9090 6 ай бұрын
They're not parentheses, we call them brackets in British English, don't let the Americans take over :-(
@rafadydkiemmacha7543
@rafadydkiemmacha7543 Ай бұрын
Is it me, or is VS Code generally quite terrible with React? I find myself fixing its bullshit autocompletion, indentation etc. all the time.
@echobucket
@echobucket 7 ай бұрын
If you would just stop making stupid const arrow functions and use the dang function keyword it wouldn't get confused about the type argument and you wouldn't have to use the comma.
@bhalsodbhavin9557
@bhalsodbhavin9557 8 ай бұрын
First view
@ColinRichardson
@ColinRichardson 8 ай бұрын
You managed to be the first view? Even though I commented a full minute before you? I am not sure that logic checks out.
@DemanaJaire
@DemanaJaire 8 ай бұрын
The fact that both of you even care.
@ColinRichardson
@ColinRichardson 8 ай бұрын
@@DemanaJaire I mean, I "could leave things being wrong".. But, then, we would still be going to libraries to get information instead of having the internet.. Progress and removing incorrect things must be done
@Keisuki
@Keisuki 8 ай бұрын
First reply
@macieja92
@macieja92 8 ай бұрын
Fuck me, hah I smiled when I realized that it's so freaking easy to understand while I've been having so many problems with understanding generics 😂
@AnthonyPaulT
@AnthonyPaulT 8 ай бұрын
can you do `extends object` instead?
@mattpocockuk
@mattpocockuk 8 ай бұрын
That's a bit looser, since arrays are also objects.
@churraskindequeijo8418
@churraskindequeijo8418 8 ай бұрын
Nice
Generics: The most intimidating TypeScript feature
18:19
Matt Pocock
Рет қаралды 176 М.
The Most Important Design Pattern in React
35:04
Cosden Solutions
Рет қаралды 48 М.
The Joker wanted to stand at the front, but unexpectedly was beaten up by Officer Rabbit
00:12
Players vs Corner Flags 🤯
00:28
LE FOOT EN VIDÉO
Рет қаралды 54 МЛН
TypeScript Generics are EASY once you know this
22:21
ByteGrad
Рет қаралды 137 М.
Infer is easier than you think
13:38
Matt Pocock
Рет қаралды 90 М.
Being Competent With Coding Is More Fun
11:13
TheVimeagen
Рет қаралды 68 М.
Enums considered harmful
9:23
Matt Pocock
Рет қаралды 206 М.
Most TS devs don't understand 'satisfies'
4:10
Matt Pocock
Рет қаралды 56 М.
Clean Code is SLOW But REQUIRED? | Prime Reacts
28:22
ThePrimeTime
Рет қаралды 307 М.
as const: the most underrated TypeScript feature
5:38
Matt Pocock
Рет қаралды 119 М.
Learn How To Use Svelte 5 Snippets
17:41
Joy of Code
Рет қаралды 7 М.
"The Life & Death of htmx" by Alexander Petros at Big Sky Dev Con 2024
23:01
Montana Programmers
Рет қаралды 59 М.
The Joker wanted to stand at the front, but unexpectedly was beaten up by Officer Rabbit
00:12