I've been searching for content to improve my shitty React codebase, and out of about 10 way more popular videos, this is the first one with some actual content. Others just tell something basic without any convincing. But your video is so much better! A bit long, so I'll watch the rest later, plus I see you left long answers to comments, which I'll obv have to read now. But for now, thanks!
Hope the rest helps you out! There are different ways to approach React components. I was aiming to fix tight coupling. In a later video I did with another group at Microsoft with a similar pattern, I also tried renderProps + useCallback, but it adds indirection. I use that pattern at my current job though. I came up with a way to do children-first with TypeScript and clever use of generics, but it requires some thought to figure out.
Hey man this is a gold mine of information. Keep it up. You should do more videos in this style with the slides. The way I learn most is when I get a short explanation of what a library/concept is first, why you need it, and why you should care. Then I like seeing an actual concrete example of how things are done using framework/example A and how the equivalent thing is done in framework/example B. Then I have the full context and can actually understand how example B solves the problems in example A and why I should even care in the first place. (think class + lifecycle vs function + hooks). This way you can gradually build on example A and B as you continue through the video and you can also isolate sections of code from example A, B or even C without needing to give full context of each to get your point across. I think this way is pretty digestible for most people and it makes sure the viewer is not lost in the middle of an explanation and they can discover why something is so elegant themselves. Anyways, liked and subbed hope to see more soon.
Thanks so much! I'd love to do more of these. I even have one ready on TypeScript but haven't had time to put it up yet (3 kids now) These styles of video take two weeks to create including all weekend and also time practicing my ad libs. Really glad you like the production value!
@@KevinGhadyani Yeah no worries I know it can get chaotic. I do have a few questions though. 1. What’s your stance on server components? Does this model still work with all the context? I’m assuming a lot of them would need to be client components to work to track the state. 2. You briefly mentioned jotai. Could you use it instead of context? 3. Opinion on tailwind now that it has exploded in popularity. I’ve personally used it for a few years now and couldn’t imagine styling an app without it or a solution very similar it. Shadcn/ui which runs on radix is also incredible to use and it looks like it uses a similar pattern you describe in the video. Would you call that children first?
@@keelangibb565 For #1, server components can track state too. The server keeps the HTML loading in the background and throws JS it generates at the client. That's how it works. So if you have state, it should retain in server components. Am I missing something? That's what my original exploration showed when I first tested it out in a different video: ruclips.net/video/6R_r6AqscqQ/видео.html&pp=ygUbcmVhY3QgMTggc3NyIGtldmluIGdoYWR5YW5p #2 YES! I've actually used Jotai 4 times now in place of context. If I need global context, I use Jotai. It's like Redux in that it's not tied to React, so you can use it to write your own logic and associate multiple frameworks or multiple React instances. This is very common with micro frontends. #3 My opinion on Tailwind hasn't changed except on one point (I'll say at the end). If you write your HTML with Tailwind classes, you're doing it wrong. You need to write Tailwind like you're writing Emotion CSS (which you shouldn't be writing inline if you want your render code to be readable). Make it type-safe (which is super difficult to do in VSCode when it's not inline) and add some helper functions so it's easy to do line-by-line (function args) rather than a stupidly long string of random classes. There are so many gotchas! Vanilla Tailwind sucks and leads to the same problems I dealt with at a marketing site job in 2012 where you literally couldn't tell what was going on with the CSS or the HTML. YUCK! I absolutely don't recommend it if you're writing HTML like it's 1994. Also, unless you're using Vite, it's tricky to get Tailwind setup correctly. You have to purge out classnames from the final compiled output or your bundle jumps up 4MB. Lastly, you cannot use Tailwind classnames. This is why you _need_ helper functions or something similar. Tailwind classnames have to be namespaced you absolutely will run into the same Global CSS issue everyone runs into when you try to scale your site or upgrade something (like the Tailwind version) or change one style in one place of the Tailwind config and hope it doesn't globally affect your whole app. I am constantly dealing with micro frontends, and all of those have different CSS considerations based on the version of the component library they're running. If Tailwind isn't namespaced, they'll all share the same Global CSS, so when certain micro apps appear on the page at the same time, it could lead to different outcomes depending on which are loading when. Good luck debugging that! It will take WEEKS. And the problems will change over time as different apps add changes. So in conclusion, yes, you can use Tailwind, but I think you need to do a lot of work to make it feasible. I would absolutely never use it out-of-the-box. And so you know, I've done 2 Tailwind projects so far successfully on side jobs, so I'm speaking from experience.
I think the weakness of moving a lot of logic to context, is that it creates an implicit coupling to the component hierarchy. Context providers need to be always on top of context consumers. There can be a case, where you want to use a child component without a ctx provider, but it's not possible with this approach. This point is also mentioned in react docs about context Api, where they prioritise component composition over context api. Second, there there is an argument to be made about readability. With prop drilling, you are at least writing explicitly how data flows through the component hierarchy. I think excessive ctx api usage has a bigger potential to become spaghetti (that's a highly opinionated argument, but still). I personally come from Vue background and Vue also has its context Api alternative, called provide/inject. And it's *explicitly* meant to be used as an escape hatch, when you see it's the only solution possible. So I'm probably biased here. My solution would be something like this: 1. Hooks don't have that issue, so I personally try to use them over provider / consumer pattern. Composition > Inheritance 2. The 'children-first' approach you mention certainly solves half of the problems, and don't have any coupling between components + avoids props , so I'm 100% with you on that one. 3. In some cases, you need to specify, that some component needs to be above another one, like in the AccordionRoot / AccordionItem example. So here, the context api is certainly cool, because there's no way you'll put AccordionItem above AccordionRoot. To move explicit, I really like to use the compound pattern, where you'd write a component like this: foo So it's extra explicit about the fact that these two components belong together, and it'll probably break if you use one, without the other. It's also what tailwind uses in the headless ui a lot. In general, the cleanness of code is in the eyes of the beholder often, and the number 1 thing we all try to avoid is 50+ props drilling 6 levels deep. And the difference of HOW to do that can be often a thing of preference
I really appreciate you watching my talk and spending the time you did to write a thorough response. # 1 To your first point, the context logic I'm proposing is only for logic components, not UI. This way, you don't run into situations where you can't compose those components using props. They also logically belong together, so the coupling there makes sense; although, you can always switch out a context consumer (like `VisibilityTarget`) with one of your own. I had to write my own component for OneForm by pulling in the `useField` hook before. I needed it for a weird situation relating to a component. Exposing that hook was meant to be clutch and only used when absolutely necessary. For everything else, the `translateProps` function sufficed. # 2 You can assign a default value to `createContext`. I always do this because I often render context consumers in Storybook and don't want to mock every context. These days, I'd prefer context be limited to logic components. With `cloneElement`, your consumers can then rely on props (as you're suggesting), but then `cloneElement` allows the medium-coupled context consumers to associated with the provider: ``` {/* props component */} ``` # 3 I completely agree that improper use of context, like you'd have with `$rootScope` or any `Provider` variant in AngularJS, can easily lead to jQuery-like code. That's why separation of concerns is so important. The point is not to simply use context, but to create building blocks with contracts, so you don't run into those situations. # 4 I'm not familiar with Vue, but I looked up the docs on `provide` and `inject` (vuejs.org/guide/components/provide-inject.html). I wouldn't see this as an escape hatch personally. Context is old-hat for me. When I did React prior to hooks and Context API, I'd write only stateless function components. Redux was the only way I had state. I'd wrap my simple reducers in a higher-order reducer that segmented state based on a `name` prop. When selecting from Redux state, I could observe only that `name` and when dispatching actions, I could also specify the name. Because it's based on the component hierarchy, React's Context API allows you to avoid the explicit `name` prop unless you need an escape hatch. It's actually a benefit and only possible with composition. # 5 I don't agree that hooks -> composition | context -> inheritance. Context is optional dependency injection. The is the opposite of inheritance. Another limitation of inheritance is only having one explicit parent. You can have multiple contexts in any given component; therefore, it's composable. # 6 I'm fine with you putting `Accordion.Root` etc. I don't do that for my slides because it's too confusing, and every character counts. I looked up headless UI and Tailwind (tailwindcss.com/blog/headless-ui-v1). This is definitely a similar pattern as you suggest. I also like being explicit. Two component libraries I worked on were setup with the object `.` pattern because exports were easier. I'm not opposed to it, but it doesn't allow for tree-shaking. I do like knowing component X and Y belong together, but that's not available on every project, so I typically use prefix namespacing instead: `AccordionRoot`, `AccordionItems`, etc. # 7 You pointed out a flaw in my design without realizing it. "there's no way you'll put AccordionItem above AccordionRoot" I've seen an accordion in an accordion on government websites. While it's bad UX, it's still something that could happen in other cases. But I thought about this more and realized you found a flaw in my design: ```
{/* this is an issue */} ``` It made me realize that putting a top-level provider means there's no way for it to provide that context 1-level deep; although, I FOUND A SOLUTION! You can provide 2 contexts in VisibilityProvider: ``` {/* uses default */} {children} ``` By doing it this way, you can shut-off the parent `VisibilityControlContext`. Sadly, this only works if it's in another `VisiblityProvider`. It won't work if you're outside of it; although, why would you be? You could create a ``; although, I don't think you should ever be getting into this situation. It's some serious code smell :p. # 8 From reading your response, I realized it might be valuable to have components able to be controlled by both props _and_ context. While you'd accept values through context, you also be able to override those with props as needed. I've built this style before when I had to support both a new (context) and old (props) API at the same time in a component library. I think this is a bit over-engineering to do it on every component unless you could find a need where it made sense. # 9 I wonder how you avoid 50+ props drilling if you don't have a pattern of principle of using context and being children-first. I've never come across an app dependent on props where that wasn't the case. The majority of apps use Redux or only context providers at the root. After the first time I presented this talk in person, people came up to me saying "I never thought I could use context like this". That was the most common feedback I'd received. # Conclusion Thank you so much for your detailed response! I love getting feedback on my talks, and you really had me thinking hard for a solution to the
Your work are truly amazing! I known about compound component a couple months ago, I think it's really cool concept till I watched this video that you show even cooler concept. Thank!
I have a mostly-perfect script from a transcription app I use. If you wanna edit the script and fix the weird stuff, I can add it to the RUclips video. I'll even pay you for your time 👍.
Hey, I've enjoyed the talk, especially until 20:00. The thing about your children first design is that it's very different from what we (as frontend devs) are used to. The problem with that is that it would be hard to get others to do it. And most importantly - they might not understand it. They might completely butcher a completely fine and reusable component. This is what I'm worried about with this approach. I've seen trunk based development and functional programming - two very good approaches in my opinion - ruin a workflow or a code, because of one or two people who didn't know what they were doing. And that's not because they were a new programmer, it's just that they were not used to the nuanses in a codebase. Again, I loved the talk, and I don't want to sound overly negative. I might give it a try, but it's possible that I will go with a more common approach c:
That's great feedback, and you're exactly right! You build tools for the people using them. I often go out of my way to pull people into best practices, but different companies have different needs. Where I'm working today, we had 1K devs rather than 50, so my ability to educate is severely limited. I heavily rely on TypeScript to enforce our intent, and really really lock down our props because long-term stability is key. They don't want people deviating, so I'm not using Children-first; although, internally, I use a renderProps inner wrapper variant with useCallback to maintain memoization. It still has passthrough props, but it fits the needs of this org. TypeScript helps a ton! I was all-JS when I originally did this talk.
Thanks a lot for this, as a beginner/intermediate software developer this kind of content that goes beyond usual RUclips's material is really valuable to level up. I went ahead on my editor to try to implement the child first pattern with cloneElem and Context but if I may suggest something I think that this format suits well for conferences but a slightly more decoupled format within several videos with executed code examples to compare the different approaches might suits RUclips better and be more accessible.
I appreciate your feedback. What might solve your problem is chapter markers. If I did break this up, I don't think anyone's gonna watch the other parts. Also, the presentation doesn't make sense without the context of the full talk. If I split these up, I'd have to re-explain why tight coupling is bad and tech debt in each part. I've also seen other RUclipsrs more successful from uploading longer videos. I've also heard that multi-part videos are a "bad practice" on RUclips.
@@KevinGhadyani Maybe making a playlist + just specifying at the beginning of each part that it only makes sens if you've watched previous videos. That way you could have more in details parts while still managing to not have a several hours monolith videos. For the format maybe you're right, I often got confused because short videos in form of series (see for example code evolution) are successful in general but it's true that the first video of the serie might have 10 to 100 times more views than the last one but I guess that's inevitable, people get excited at the beginning but then quickly give up. In the other hand there are 10 hours tutorial videos that got a massive amount of views, but at the end how long people watch them ? I don't have the stats but if it follows the previous pattern I'm confident people just watch few minutes. It feels like people see them as "a full course" and just jump into them. Don't know if you know Jack Herrington ? He makes videos about JS/TS and for me he nailed the perfect balance
Amazing talk, could have used a bridge to the various styles of state managers (single store, local store), but enjoyed it a lot. Thank you for taking the time !
Hi Kevin, great video. Strange I didn't find it earlier. One question: you mention that using className prop is an anti-pattern. What would be the right way to change the style of a component from the parent? I could not find any good article about this and to be frank a lot of articles on the net are actually about using the className prop.
Use props to change the styles on a component. Internally, you can use Emotion, Tailwind, whatever, but outside, don't allow passing arbitrary class names.
Your example of Accordion could be simplified by using data- and ARIA attributes to annotate your components and make them semantically correct, make them stylable and easy to test. The component itself doesn't need to know any styling, except for maybe orientation, which also can affect behaviour. There's no need for cloneElement here, so implementation is simpler, too. ARIA attributes are often missed. By themselves ul and li does not represent an accordion, it represents a bullet point list semantically. Accordion, as the name suggests, visually collapse and expand sections. Sections have headings and a body, which does not fit the semantics of unordered lists, which are typically just content. You may as well use divs and ARIA attributes to properly specify state, labels and roles for the content. Using ARIA labels to annotate the behaviour and state of a component is important for accessibility. Additionally you can select those ARIA attributes in CSS based on the state, for free. Data attributes are useful to give meaning to the component outside of it and without leaking abstractions. It makes your components simpler to use, more accessible and makes it easily testable in E2E tests without leaking implementation details. It's all in the DOM.
I think I'm understanding you correctly. But the examples I gave had a single Accordion component that took an isVisible prop and that's it. All the visibility logic is handled in separate components. But handling the complex aria associations are automatically handled by the logic components and passed into the accordion. A list of accordions would be wrapped by a ul and a bunch of li right? Did I say something counter to your comment?
This is the implementation from the presentation. I think that'll explain it more: github.com/Sawtaytoes/children-first-components/tree/master/src I'm changing this API in the future for TypeScript awareness using the builder pattern (TypeScript-first shown in another video of mine), but the new API will still retain almost all principles of children-first design except one thing: plug 'n play convenience. You get a bit of optional boilerplate for the benefit of better type documentation and a complete avoidance of cloneElement. This was brought up because cloneElement is seen negatively by React devs and doesn't even work in Solid.js without major compromises. The new pattern will be more universal.
@@KevinGhadyani I was thinking of doing it a bit differently without the need for cloneElement; For example, in case of Radix UI, it accepts the state (either controlled or uncontrolled, based on `default*` prefix) and a event listener in the root component. This way it can pass that state through to the child components that observes from the same context. This also makes it easier to hook up state, without the need to add conditions inside your component, but just by passing state and some dispatch in the root. The AccordionItem doesn't make much sense without its root anyway, neither does the AccordionTrigger or AccordionContent outside of the item-they are naturally coupled (compound). This could also apply to your generic Visibility component. The user's own content is wrapped by these outer components anyway, so you already have all the power without the need to clone.
I love the way you have dived deep into design patterns, but one main thing I am unsure about is that in the docs react team has mentioned not to use cloneElement and they have deprecated the api as well . So what’s your take on that? Would love to hear
The React team doesn't necessarily support all use cases, but many libraries use `cloneElement` internally. I've been looking at alternatives for a while now because I never liked how this was invisible and difficult to enforce in TypeScript. On the other hand, I figured out how to make render props fit my needs with memoization. Months later, in an interview with a Microsoft dev, he pointed out I could use useCallback and get a similar effect! It's not exactly the same, but it fixes my biggest gripe of render props. Another friend pointed out you could wrap these component functions to create new ones that had the functionality you wanted built-in. Where I work right now, they wanted render props with useCallback, so that's what I have. I haven't experimented with new ways to fix this since, but I'm sure there will be better ways in the future.
@@KevinGhadyani You can optimise it further, the problem of useCallback is that if you have nested components in it, no matter you need to re-render only the last one, useCallback will execute recreate the function from scratch and as a result re-render the whole tree, absolutely disgusting. instead you can come up with a solution that uses refs to keep in memory the instance of the function and only pass the updated props along with the render props. I did a hook sometime ago for fun but then i deleted it by mistake the end result looked something like this: } /> CoolChild can also have many children, but if your prop update should only cause a re-render of CoolChild then only CoolChild will re-render, if your prop changes only need to re-render a child, then only the child will. slot is actualy hook that returns a function and internally uses ref to keep the reference of all the stuff over the current comp re-renders. The only downsides of this is that list are a problem, you can't use "slot" in a map, because hooks need to be executed in same order but if you have list you may end-up with adding or removing stuff that is not fine. However i for now discarded this path and try to use only regular children or passing children in props, and avoid render functions. I think it keeps the design clean and open to a ton of possible custom use cases, this is also a pattern that can be re-used in any other framework
I'm still digesting this. I think in general I agree with a lot. I'm the one making the stink of using good patterns and avoiding tech debt at my company. A lot of my coworkers can see tech debt after the fact, but they can't see the actual cause. It's usually just, "we couldn't predict that this is what we'd have to do." Sure, that's true in some cases, but you can still maintain a lot of flexibility. And this talk showcases that with your building blocks concept. cloneElement frankly scares me lol. I think its biggest strength is also its biggest weakness: that to the consumer, it's "magic" that "just works." I agree that I shouldn't care *how* something I'm using works, just how *I* need to use it. I think I get how you're using it here though. At first I thought you were doing the compound component pattern with that, but it seems you're doing that with context where appropriate. There are certainly situations where there could be another layer between a parent part of a compound component and a child part. But using components that clone their children to inject props is certainly interesting. It's like a more declarative HOC that can also be used inline. I know you don't use Typescript, but I'm curious if there's a way to type this. Probably is. Like "I need an instance of a component that could take this prop." I think it'd be something like ReactElement void }>. As someone else mentioned, I would also like to see examples with more depth. I don't know if you could write up a gist or something. I know coming up with examples that imitate real world use cases can be difficult, but with the video format and the slides only containing so much information, it's hard to keep a mental image of what the code might look like.
Thanks for your response! You're totally about people not seeing the cause of tech debt. I've also worked at numerous places where they _always_ say they couldn't have known, but the design was such that it was absolutely gong to cause it. # 1 `cloneElement` was also scary to me when I first used it. I tried it once on a `Button` where they would pass in an `` component, the only one we accepted, and I modified the icon with the correct `size` relative to the button. This is tight coupling but also my first time using it. # 2 You're right to point out this isn't regular compound components; context is key. cloneElement is only used for the presentational UI components. The logic itself is tucked away in context. Glad to hear you understood this deeply! 👍 # 3 I like the idea of relating it to higher-order components. Standard `withTheme` and `connect` hocs are static, but render props is a dynamic version which is why you can replace `connect` with `` (github.com/reduxjs/react-redux/issues/920). To remove boilerplate and get the same effect with standard React, cloneElement is the dynamic equivalent. # 4 I personally don't use TypeScript on home projects (at least not yet) and definitely not for presentations since I wanna keep things simple. On the other hand, I'm forced to use TypeScript at my new job, so I've been learning it since March. I was also thinking of somehow modifying `children: ReactElement`. If you figure out a way, please tell me, and I'll put up a video on it. I can even Zoom call you in the video since you'd be the one who solved it. I haven't had to solve this at work just yet, but I will later this week. # 5 You're correct about the slides being limited. I focused on the API and not the implementation for that reason. It's also a limitation of what people wanna watch on RUclips. I even moved all my live-coding videos to a separate channel because they were killing this one. I have an implementation of Picker available on CodeSandbox: codesandbox.io/s/picker-component-architecture-tq0jk?file=/src/Picker.jsx. The Visibility components I've written for companies, so I don't have any available on CodeSandbox. I was honestly thinking of building a library instead. It's not like this couldn't be open source. It's literally the simplest set of building blocks that you'd use 100 times in your apps. Problem is that building a library would take my free time, and I get paid to do it at work 🤷♂️.
@@KevinGhadyani I think the difficulty with typing it is going to be for components that need the prop that is being injected by the parent when it's cloned. TS doesn't know that the cloning is happening. Now, you could make the prop always optional, which is kind of fitting (a button doesn't *need* onClick technically) but this doesn't seem like a solution that works universally.
Actually, it should be optional. Why is onClick required? What if you're testing the button's text? Why tightly couple the onClick mock in that test? I actually advocate optional props with sane defaults normally anyway. Existing props will need to be mocked when writing regular code or the cloning won't work Like with TypeScript vs JS, optional props are a different mindset.
What's upsetting to me is realizing I missed that. When I did this in person, someone asked, so I answered it. I have plans to do a short video in the future on "sane defaults", my own term.
@@KevinGhadyani We may just disagree on this, but for me, sometimes a "sane default" is to throw an error. For example, you have these parent-child relationships with these compound components that utilize context. In the example code you shared in this thread, you default the context value to the same shape as you'd expect (which certainly is useful for inline documentation) with empty values. For situations like that, I tend to leave the default context value as undefined. Then in the consuming child component, I throw a descriptive error if the context's value is undefined, saying that the context provider with a valid value was expected to exist. If I provide type-compliant defaults, I'm left with situations where it could silently fail if someone forgot to use the parent component. Then that's extra time spent debugging for a pretty simple bug with a simple solution. Is there something I'm missing about providing these default empty values?
I built a library out of these logic components, but I haven't published it yet. You can find them here: github.com/Sawtaytoes/children-first-components/tree/master/src
IMHO the technical part of explaining what is props and children was good. The part that's crazy to me is the obsession to make things more complicated that it needs to be. The take in this video is that you should take the responsibility that the other devs gonna produce bad code and the solution is to write a complex and difficult to read code to mitigate it.
I'm not exactly sure I understand your point, but I'll respond the best I can :). I take a different approach at each company I go to based on the needs of the org and the existing codebase. This is just one solution you can use to solve the problem of tight coupling, but not something that works everywhere you go. In general though, the more complex your library, the less complex the code consumers need when consuming it. Where I work now, I have a different approach than this video. Instead of component usage freedom, they want API stability and ease-of-use. Now we're creating one component for each feature rather than a bunch of them that you assemble because that follows the design system better (unlike the patterns I had at this other company). It's a 180 degree difference in component design. The goal of TypeScript and other coding patterns is to make it dead simple to write code the intended way, so other devs can't screw it up.
I actually have quite a few videos that need to be posted and one talk about TypeScript, but I just haven't had time. I need to hire someone to manage all this.
This is great, what I don't quite get is how does the make the inside it trigger the event needed for the logic of the modal? Does it clone the child with an extra onClick prop inserted somehow?
What specifically do you want to see on slides? I tried removing cruft so there's less code to read for the 2-5 seconds it's on screen. Are you wanting to see the implementation or do I need more code in the slide? Does this help? github.com/Sawtaytoes/children-first-components/tree/master/src Go to Visibility or Picker stories to see uses.
@@KevinGhadyani Yeah that helps a lot! 👍 I'll dig through it and see if I can understand everything. It was hard for me to understand how the 'children-first' approach without seeing the actual implementation of all the pieces. Part of the reason is probably that I'm not super familiar with advanced React concepts yet. For me personally, especially if it's a video, I like to see complete examples, I can pause if I need some more time.
I appreciate it! I'd love to make a course especially with the passive income source. Of the few courses I've tried for work, I've never gotten anything out of them, and I've never finished any either. I don't really think I'm qualified to do courses. I'd hope my RUclips videos provide enough information.
@@KevinGhadyani Bummer... A course on how to properly design components would be awesome. Anyway, do you have source code with all the examples above? I would like to look at them in order to learn more. Some of the stuff is just too vague. BTW, I'm pretty sure you are qualified. :D
I think I am fairly smart but I had to watch this twice to grasp the concept, and that is with 8 years React experience, I tried slowing it down to 0.75 speed but it makes you sound drunk... lol. Thanks though... I am sure after a good nights rest it will make sense. I am always bemoaning counter increment examples, now I wish there was one. Perhaps I will just try it out myself.
this is the kind of video I wanted to see when googling "advanced react patterns". I only got all those generic ass videos explaining low or medium level react concepts over and over again.
Am I wrong 🤔 I feel like building components like this is mostly suitable in vue than in react where one could easily register the library globally and use anywhere without having to import stuffs . Cause imagine creating a sign up form, a Modal, a drop down in a single page , you would have to import a lot of things, import this import that ooh God 🤣 this is interesting
I think it's fine. I often import a bunch of stuff. Never used Vue, but if you've seen the popular UI library Material-UI, they also make you import a bunch. From using OneForm and these other methods, you get used to it. It makes the DOM behavior very clean.
I would say CSS-in-JS is also a huge antipattern. The good separation of concerns here is to have an app visual language that is translated into CSS reset/sane defaults and as CSS is an exception based language, you _deviate_ from the sane defaults in your components, meaning most of your codebase the styling will be very thin. However this usually does not happen as most companies struggle with bottom-up anarchy and designers running after developers who run after business requirements.
@@KevinGhadyani Sorry man, sorry for the late reply, first of all "CSS-in-JS" not the other way around, probably I was quite tired. I think I tried telling too many things in 1 comment. When designing effective components, it's important to consider the styling. CSS is a language which provides the best results when the design follows a top-bottom approach: you define your base style, font sizes, distances, colors, then you create a limited set of containers (aka "visual language" of the site). And finally, for little details, you define exceptions from these rules. With this approach you have a very lean set of cacheable CSS rules, that is quick to download, quick to execute. If you are creating React components one must not work against this optimum. In the second part I did a bad job explaining that most of us usually not work like this in a top-bottom approach, we are not handed a consistent design language by the company we arrive to, nor a limited set of smartly designed responsive containers, rather, we get a Figma design and we try our best, without wasting too much time on the big picture. That was the "bottom-up anarchy" thing, that because of how corporate engineering works, we usually just do what's needed to finish a task, resulting in defining the same CSS rules over and over (with TailwindCSS explicitly encouraging this behavior for example). So, we don't do the right CSS/component architecture because of how disconnected corporate teams are.
Back when I was working on the game, I was doing a lot of stuff all by myself, but I was a junior-level dev. I'd sleep once every 2 days sometimes. It wasn't every day each week, but it was quite often. I remember being up for so long my vision would get blurry. I slept when people stopped having things for me to review, but because everyone was global, I was up around the clock.
I've been searching for content to improve my shitty React codebase, and out of about 10 way more popular videos, this is the first one with some actual content. Others just tell something basic without any convincing. But your video is so much better! A bit long, so I'll watch the rest later, plus I see you left long answers to comments, which I'll obv have to read now. But for now, thanks!
Hope the rest helps you out! There are different ways to approach React components. I was aiming to fix tight coupling.
In a later video I did with another group at Microsoft with a similar pattern, I also tried renderProps + useCallback, but it adds indirection. I use that pattern at my current job though.
I came up with a way to do children-first with TypeScript and clever use of generics, but it requires some thought to figure out.
Hey man this is a gold mine of information. Keep it up. You should do more videos in this style with the slides.
The way I learn most is when I get a short explanation of what a library/concept is first, why you need it, and why you should care. Then I like seeing an actual concrete example of how things are done using framework/example A and how the equivalent thing is done in framework/example B. Then I have the full context and can actually understand how example B solves the problems in example A and why I should even care in the first place. (think class + lifecycle vs function + hooks).
This way you can gradually build on example A and B as you continue through the video and you can also isolate sections of code from example A, B or even C without needing to give full context of each to get your point across.
I think this way is pretty digestible for most people and it makes sure the viewer is not lost in the middle of an explanation and they can discover why something is so elegant themselves.
Anyways, liked and subbed hope to see more soon.
Thanks so much! I'd love to do more of these. I even have one ready on TypeScript but haven't had time to put it up yet (3 kids now)
These styles of video take two weeks to create including all weekend and also time practicing my ad libs.
Really glad you like the production value!
@@KevinGhadyani Yeah no worries I know it can get chaotic. I do have a few questions though.
1. What’s your stance on server components? Does this model still work with all the context? I’m assuming a lot of them would need to be client components to work to track the state.
2. You briefly mentioned jotai. Could you use it instead of context?
3. Opinion on tailwind now that it has exploded in popularity. I’ve personally used it for a few years now and couldn’t imagine styling an app without it or a solution very similar it. Shadcn/ui which runs on radix is also incredible to use and it looks like it uses a similar pattern you describe in the video. Would you call that children first?
@@keelangibb565 For #1, server components can track state too. The server keeps the HTML loading in the background and throws JS it generates at the client. That's how it works. So if you have state, it should retain in server components. Am I missing something? That's what my original exploration showed when I first tested it out in a different video: ruclips.net/video/6R_r6AqscqQ/видео.html&pp=ygUbcmVhY3QgMTggc3NyIGtldmluIGdoYWR5YW5p
#2 YES! I've actually used Jotai 4 times now in place of context. If I need global context, I use Jotai. It's like Redux in that it's not tied to React, so you can use it to write your own logic and associate multiple frameworks or multiple React instances. This is very common with micro frontends.
#3 My opinion on Tailwind hasn't changed except on one point (I'll say at the end). If you write your HTML with Tailwind classes, you're doing it wrong. You need to write Tailwind like you're writing Emotion CSS (which you shouldn't be writing inline if you want your render code to be readable). Make it type-safe (which is super difficult to do in VSCode when it's not inline) and add some helper functions so it's easy to do line-by-line (function args) rather than a stupidly long string of random classes. There are so many gotchas!
Vanilla Tailwind sucks and leads to the same problems I dealt with at a marketing site job in 2012 where you literally couldn't tell what was going on with the CSS or the HTML. YUCK! I absolutely don't recommend it if you're writing HTML like it's 1994. Also, unless you're using Vite, it's tricky to get Tailwind setup correctly. You have to purge out classnames from the final compiled output or your bundle jumps up 4MB.
Lastly, you cannot use Tailwind classnames. This is why you _need_ helper functions or something similar. Tailwind classnames have to be namespaced you absolutely will run into the same Global CSS issue everyone runs into when you try to scale your site or upgrade something (like the Tailwind version) or change one style in one place of the Tailwind config and hope it doesn't globally affect your whole app.
I am constantly dealing with micro frontends, and all of those have different CSS considerations based on the version of the component library they're running. If Tailwind isn't namespaced, they'll all share the same Global CSS, so when certain micro apps appear on the page at the same time, it could lead to different outcomes depending on which are loading when. Good luck debugging that! It will take WEEKS. And the problems will change over time as different apps add changes.
So in conclusion, yes, you can use Tailwind, but I think you need to do a lot of work to make it feasible. I would absolutely never use it out-of-the-box. And so you know, I've done 2 Tailwind projects so far successfully on side jobs, so I'm speaking from experience.
I think the weakness of moving a lot of logic to context, is that it creates an implicit coupling to the component hierarchy. Context providers need to be always on top of context consumers. There can be a case, where you want to use a child component without a ctx provider, but it's not possible with this approach. This point is also mentioned in react docs about context Api, where they prioritise component composition over context api.
Second, there there is an argument to be made about readability. With prop drilling, you are at least writing explicitly how data flows through the component hierarchy. I think excessive ctx api usage has a bigger potential to become spaghetti (that's a highly opinionated argument, but still).
I personally come from Vue background and Vue also has its context Api alternative, called provide/inject. And it's *explicitly* meant to be used as an escape hatch, when you see it's the only solution possible. So I'm probably biased here.
My solution would be something like this:
1. Hooks don't have that issue, so I personally try to use them over provider / consumer pattern. Composition > Inheritance
2. The 'children-first' approach you mention certainly solves half of the problems, and don't have any coupling between components + avoids props , so I'm 100% with you on that one.
3. In some cases, you need to specify, that some component needs to be above another one, like in the AccordionRoot / AccordionItem example. So here, the context api is certainly cool, because there's no way you'll put AccordionItem above AccordionRoot. To move explicit, I really like to use the compound pattern, where you'd write a component like this:
foo
So it's extra explicit about the fact that these two components belong together, and it'll probably break if you use one, without the other. It's also what tailwind uses in the headless ui a lot.
In general, the cleanness of code is in the eyes of the beholder often, and the number 1 thing we all try to avoid is 50+ props drilling 6 levels deep. And the difference of HOW to do that can be often a thing of preference
I really appreciate you watching my talk and spending the time you did to write a thorough response.
# 1
To your first point, the context logic I'm proposing is only for logic components, not UI.
This way, you don't run into situations where you can't compose those components using props. They also logically belong together, so the coupling there makes sense; although, you can always switch out a context consumer (like `VisibilityTarget`) with one of your own.
I had to write my own component for OneForm by pulling in the `useField` hook before. I needed it for a weird situation relating to a component. Exposing that hook was meant to be clutch and only used when absolutely necessary. For everything else, the `translateProps` function sufficed.
# 2
You can assign a default value to `createContext`. I always do this because I often render context consumers in Storybook and don't want to mock every context.
These days, I'd prefer context be limited to logic components. With `cloneElement`, your consumers can then rely on props (as you're suggesting), but then `cloneElement` allows the medium-coupled context consumers to associated with the provider:
```
{/* props component */}
```
# 3
I completely agree that improper use of context, like you'd have with `$rootScope` or any `Provider` variant in AngularJS, can easily lead to jQuery-like code. That's why separation of concerns is so important.
The point is not to simply use context, but to create building blocks with contracts, so you don't run into those situations.
# 4
I'm not familiar with Vue, but I looked up the docs on `provide` and `inject` (vuejs.org/guide/components/provide-inject.html). I wouldn't see this as an escape hatch personally.
Context is old-hat for me. When I did React prior to hooks and Context API, I'd write only stateless function components. Redux was the only way I had state.
I'd wrap my simple reducers in a higher-order reducer that segmented state based on a `name` prop. When selecting from Redux state, I could observe only that `name` and when dispatching actions, I could also specify the name.
Because it's based on the component hierarchy, React's Context API allows you to avoid the explicit `name` prop unless you need an escape hatch. It's actually a benefit and only possible with composition.
# 5
I don't agree that hooks -> composition | context -> inheritance.
Context is optional dependency injection. The is the opposite of inheritance. Another limitation of inheritance is only having one explicit parent. You can have multiple contexts in any given component; therefore, it's composable.
# 6
I'm fine with you putting `Accordion.Root` etc. I don't do that for my slides because it's too confusing, and every character counts.
I looked up headless UI and Tailwind (tailwindcss.com/blog/headless-ui-v1). This is definitely a similar pattern as you suggest. I also like being explicit.
Two component libraries I worked on were setup with the object `.` pattern because exports were easier. I'm not opposed to it, but it doesn't allow for tree-shaking.
I do like knowing component X and Y belong together, but that's not available on every project, so I typically use prefix namespacing instead: `AccordionRoot`, `AccordionItems`, etc.
# 7
You pointed out a flaw in my design without realizing it.
"there's no way you'll put AccordionItem above AccordionRoot"
I've seen an accordion in an accordion on government websites. While it's bad UX, it's still something that could happen in other cases.
But I thought about this more and realized you found a flaw in my design:
```
{/* this is an issue */}
```
It made me realize that putting a top-level provider means there's no way for it to provide that context 1-level deep; although, I FOUND A SOLUTION!
You can provide 2 contexts in VisibilityProvider:
```
{/* uses default */}
{children}
```
By doing it this way, you can shut-off the parent `VisibilityControlContext`.
Sadly, this only works if it's in another `VisiblityProvider`. It won't work if you're outside of it; although, why would you be?
You could create a ``; although, I don't think you should ever be getting into this situation. It's some serious code smell :p.
# 8
From reading your response, I realized it might be valuable to have components able to be controlled by both props _and_ context.
While you'd accept values through context, you also be able to override those with props as needed. I've built this style before when I had to support both a new (context) and old (props) API at the same time in a component library.
I think this is a bit over-engineering to do it on every component unless you could find a need where it made sense.
# 9
I wonder how you avoid 50+ props drilling if you don't have a pattern of principle of using context and being children-first.
I've never come across an app dependent on props where that wasn't the case.
The majority of apps use Redux or only context providers at the root. After the first time I presented this talk in person, people came up to me saying "I never thought I could use context like this". That was the most common feedback I'd received.
# Conclusion
Thank you so much for your detailed response! I love getting feedback on my talks, and you really had me thinking hard for a solution to the
Your work are truly amazing! I known about compound component a couple months ago, I think it's really cool concept till I watched this video that you show even cooler concept. Thank!
Awesome! Worth watching over and over again. Would be even better if having subtitles.
I have a mostly-perfect script from a transcription app I use. If you wanna edit the script and fix the weird stuff, I can add it to the RUclips video. I'll even pay you for your time 👍.
@@KevinGhadyani I can write Russian and English subtitles for you. Are you still interested?
That's awesome! How would you add them?
First 10 minutes: never heard components explained better
Man, that's great to hear thanks! ;)
Hey, I've enjoyed the talk, especially until 20:00. The thing about your children first design is that it's very different from what we (as frontend devs) are used to.
The problem with that is that it would be hard to get others to do it. And most importantly - they might not understand it. They might completely butcher a completely fine and reusable component. This is what I'm worried about with this approach.
I've seen trunk based development and functional programming - two very good approaches in my opinion - ruin a workflow or a code, because of one or two people who didn't know what they were doing. And that's not because they were a new programmer, it's just that they were not used to the nuanses in a codebase.
Again, I loved the talk, and I don't want to sound overly negative. I might give it a try, but it's possible that I will go with a more common approach c:
That's great feedback, and you're exactly right! You build tools for the people using them. I often go out of my way to pull people into best practices, but different companies have different needs.
Where I'm working today, we had 1K devs rather than 50, so my ability to educate is severely limited. I heavily rely on TypeScript to enforce our intent, and really really lock down our props because long-term stability is key. They don't want people deviating, so I'm not using Children-first; although, internally, I use a renderProps inner wrapper variant with useCallback to maintain memoization. It still has passthrough props, but it fits the needs of this org.
TypeScript helps a ton! I was all-JS when I originally did this talk.
Thanks a lot for this, as a beginner/intermediate software developer this kind of content that goes beyond usual RUclips's material is really valuable to level up.
I went ahead on my editor to try to implement the child first pattern with cloneElem and Context but if I may suggest something I think that this format suits well for conferences but a slightly more decoupled format within several videos with executed code examples to compare the different approaches might suits RUclips better and be more accessible.
I appreciate your feedback. What might solve your problem is chapter markers.
If I did break this up, I don't think anyone's gonna watch the other parts.
Also, the presentation doesn't make sense without the context of the full talk.
If I split these up, I'd have to re-explain why tight coupling is bad and tech debt in each part.
I've also seen other RUclipsrs more successful from uploading longer videos. I've also heard that multi-part videos are a "bad practice" on RUclips.
@@KevinGhadyani Maybe making a playlist + just specifying at the beginning of each part that it only makes sens if you've watched previous videos. That way you could have more in details parts while still managing to not have a several hours monolith videos.
For the format maybe you're right, I often got confused because short videos in form of series (see for example code evolution) are successful in general but it's true that the first video of the serie might have 10 to 100 times more views than the last one but I guess that's inevitable, people get excited at the beginning but then quickly give up.
In the other hand there are 10 hours tutorial videos that got a massive amount of views, but at the end how long people watch them ? I don't have the stats but if it follows the previous pattern I'm confident people just watch few minutes. It feels like people see them as "a full course" and just jump into them.
Don't know if you know Jack Herrington ? He makes videos about JS/TS and for me he nailed the perfect balance
I think chapters within long video is more that sufficient to keep track of last watched part. Keep it up.
I Liked the video 👍
Amazing talk, could have used a bridge to the various styles of state managers (single store, local store), but enjoyed it a lot. Thank you for taking the time !
Hi Kevin, great video. Strange I didn't find it earlier.
One question: you mention that using className prop is an anti-pattern.
What would be the right way to change the style of a component from the parent?
I could not find any good article about this and to be frank a lot of articles on the net are actually about using the className prop.
Use props to change the styles on a component.
Internally, you can use Emotion, Tailwind, whatever, but outside, don't allow passing arbitrary class names.
This is what real HTML programming looks like!
Your example of Accordion could be simplified by using data- and ARIA attributes to annotate your components and make them semantically correct, make them stylable and easy to test. The component itself doesn't need to know any styling, except for maybe orientation, which also can affect behaviour. There's no need for cloneElement here, so implementation is simpler, too.
ARIA attributes are often missed. By themselves ul and li does not represent an accordion, it represents a bullet point list semantically. Accordion, as the name suggests, visually collapse and expand sections. Sections have headings and a body, which does not fit the semantics of unordered lists, which are typically just content.
You may as well use divs and ARIA attributes to properly specify state, labels and roles for the content. Using ARIA labels to annotate the behaviour and state of a component is important for accessibility. Additionally you can select those ARIA attributes in CSS based on the state, for free. Data attributes are useful to give meaning to the component outside of it and without leaking abstractions.
It makes your components simpler to use, more accessible and makes it easily testable in E2E tests without leaking implementation details. It's all in the DOM.
I think I'm understanding you correctly. But the examples I gave had a single Accordion component that took an isVisible prop and that's it. All the visibility logic is handled in separate components. But handling the complex aria associations are automatically handled by the logic components and passed into the accordion.
A list of accordions would be wrapped by a ul and a bunch of li right? Did I say something counter to your comment?
This is the implementation from the presentation. I think that'll explain it more: github.com/Sawtaytoes/children-first-components/tree/master/src
I'm changing this API in the future for TypeScript awareness using the builder pattern (TypeScript-first shown in another video of mine), but the new API will still retain almost all principles of children-first design except one thing: plug 'n play convenience. You get a bit of optional boilerplate for the benefit of better type documentation and a complete avoidance of cloneElement.
This was brought up because cloneElement is seen negatively by React devs and doesn't even work in Solid.js without major compromises. The new pattern will be more universal.
@@KevinGhadyani I was thinking of doing it a bit differently without the need for cloneElement;
For example, in case of Radix UI, it accepts the state (either controlled or uncontrolled, based on `default*` prefix) and a event listener in the root component. This way it can pass that state through to the child components that observes from the same context.
This also makes it easier to hook up state, without the need to add conditions inside your component, but just by passing state and some dispatch in the root.
The AccordionItem doesn't make much sense without its root anyway, neither does the AccordionTrigger or AccordionContent outside of the item-they are naturally coupled (compound).
This could also apply to your generic Visibility component. The user's own content is wrapped by these outer components anyway, so you already have all the power without the need to clone.
I love the way you have dived deep into design patterns, but one main thing I am unsure about is that in the docs react team has mentioned not to use cloneElement and they have deprecated the api as well . So what’s your take on that? Would love to hear
The React team doesn't necessarily support all use cases, but many libraries use `cloneElement` internally.
I've been looking at alternatives for a while now because I never liked how this was invisible and difficult to enforce in TypeScript.
On the other hand, I figured out how to make render props fit my needs with memoization. Months later, in an interview with a Microsoft dev, he pointed out I could use useCallback and get a similar effect! It's not exactly the same, but it fixes my biggest gripe of render props.
Another friend pointed out you could wrap these component functions to create new ones that had the functionality you wanted built-in.
Where I work right now, they wanted render props with useCallback, so that's what I have. I haven't experimented with new ways to fix this since, but I'm sure there will be better ways in the future.
@@KevinGhadyani You can optimise it further, the problem of useCallback is that if you have nested components in it, no matter you need to re-render only the last one, useCallback will execute recreate the function from scratch and as a result re-render the whole tree, absolutely disgusting.
instead you can come up with a solution that uses refs to keep in memory the instance of the function and only pass the updated props along with the render props. I did a hook sometime ago for fun but then i deleted it by mistake
the end result looked something like this:
}
/>
CoolChild can also have many children, but if your prop update should only cause a re-render of CoolChild then only CoolChild will re-render, if your prop changes only need to re-render a child, then only the child will.
slot is actualy hook that returns a function and internally uses ref to keep the reference of all the stuff over the current comp re-renders.
The only downsides of this is that list are a problem, you can't use "slot" in a map, because hooks need to be executed in same order but if you have list you may end-up with adding or removing stuff that is not fine.
However i for now discarded this path and try to use only regular children or passing children in props, and avoid render functions. I think it keeps the design clean and open to a ton of possible custom use cases, this is also a pattern that can be re-used in any other framework
I'm still digesting this. I think in general I agree with a lot. I'm the one making the stink of using good patterns and avoiding tech debt at my company. A lot of my coworkers can see tech debt after the fact, but they can't see the actual cause. It's usually just, "we couldn't predict that this is what we'd have to do." Sure, that's true in some cases, but you can still maintain a lot of flexibility. And this talk showcases that with your building blocks concept.
cloneElement frankly scares me lol. I think its biggest strength is also its biggest weakness: that to the consumer, it's "magic" that "just works." I agree that I shouldn't care *how* something I'm using works, just how *I* need to use it. I think I get how you're using it here though. At first I thought you were doing the compound component pattern with that, but it seems you're doing that with context where appropriate. There are certainly situations where there could be another layer between a parent part of a compound component and a child part. But using components that clone their children to inject props is certainly interesting. It's like a more declarative HOC that can also be used inline. I know you don't use Typescript, but I'm curious if there's a way to type this. Probably is. Like "I need an instance of a component that could take this prop." I think it'd be something like ReactElement void }>.
As someone else mentioned, I would also like to see examples with more depth. I don't know if you could write up a gist or something. I know coming up with examples that imitate real world use cases can be difficult, but with the video format and the slides only containing so much information, it's hard to keep a mental image of what the code might look like.
Thanks for your response! You're totally about people not seeing the cause of tech debt. I've also worked at numerous places where they _always_ say they couldn't have known, but the design was such that it was absolutely gong to cause it.
# 1
`cloneElement` was also scary to me when I first used it. I tried it once on a `Button` where they would pass in an `` component, the only one we accepted, and I modified the icon with the correct `size` relative to the button. This is tight coupling but also my first time using it.
# 2
You're right to point out this isn't regular compound components; context is key. cloneElement is only used for the presentational UI components. The logic itself is tucked away in context. Glad to hear you understood this deeply! 👍
# 3
I like the idea of relating it to higher-order components. Standard `withTheme` and `connect` hocs are static, but render props is a dynamic version which is why you can replace `connect` with `` (github.com/reduxjs/react-redux/issues/920). To remove boilerplate and get the same effect with standard React, cloneElement is the dynamic equivalent.
# 4
I personally don't use TypeScript on home projects (at least not yet) and definitely not for presentations since I wanna keep things simple. On the other hand, I'm forced to use TypeScript at my new job, so I've been learning it since March. I was also thinking of somehow modifying `children: ReactElement`. If you figure out a way, please tell me, and I'll put up a video on it. I can even Zoom call you in the video since you'd be the one who solved it. I haven't had to solve this at work just yet, but I will later this week.
# 5
You're correct about the slides being limited. I focused on the API and not the implementation for that reason. It's also a limitation of what people wanna watch on RUclips. I even moved all my live-coding videos to a separate channel because they were killing this one.
I have an implementation of Picker available on CodeSandbox: codesandbox.io/s/picker-component-architecture-tq0jk?file=/src/Picker.jsx.
The Visibility components I've written for companies, so I don't have any available on CodeSandbox. I was honestly thinking of building a library instead. It's not like this couldn't be open source. It's literally the simplest set of building blocks that you'd use 100 times in your apps. Problem is that building a library would take my free time, and I get paid to do it at work 🤷♂️.
@@KevinGhadyani I think the difficulty with typing it is going to be for components that need the prop that is being injected by the parent when it's cloned. TS doesn't know that the cloning is happening. Now, you could make the prop always optional, which is kind of fitting (a button doesn't *need* onClick technically) but this doesn't seem like a solution that works universally.
Actually, it should be optional. Why is onClick required? What if you're testing the button's text? Why tightly couple the onClick mock in that test?
I actually advocate optional props with sane defaults normally anyway. Existing props will need to be mocked when writing regular code or the cloning won't work
Like with TypeScript vs JS, optional props are a different mindset.
What's upsetting to me is realizing I missed that. When I did this in person, someone asked, so I answered it.
I have plans to do a short video in the future on "sane defaults", my own term.
@@KevinGhadyani We may just disagree on this, but for me, sometimes a "sane default" is to throw an error. For example, you have these parent-child relationships with these compound components that utilize context. In the example code you shared in this thread, you default the context value to the same shape as you'd expect (which certainly is useful for inline documentation) with empty values. For situations like that, I tend to leave the default context value as undefined. Then in the consuming child component, I throw a descriptive error if the context's value is undefined, saying that the context provider with a valid value was expected to exist. If I provide type-compliant defaults, I'm left with situations where it could silently fail if someone forgot to use the parent component. Then that's extra time spent debugging for a pretty simple bug with a simple solution.
Is there something I'm missing about providing these default empty values?
Great talk! but if you're not going to show the code for a lot of these examples, I think a link to a github repo would be helpful
I built a library out of these logic components, but I haven't published it yet. You can find them here: github.com/Sawtaytoes/children-first-components/tree/master/src
@@KevinGhadyani thanks!
IMHO the technical part of explaining what is props and children was good. The part that's crazy to me is the obsession to make things more complicated that it needs to be. The take in this video is that you should take the responsibility that the other devs gonna produce bad code and the solution is to write a complex and difficult to read code to mitigate it.
I'm not exactly sure I understand your point, but I'll respond the best I can :).
I take a different approach at each company I go to based on the needs of the org and the existing codebase. This is just one solution you can use to solve the problem of tight coupling, but not something that works everywhere you go.
In general though, the more complex your library, the less complex the code consumers need when consuming it.
Where I work now, I have a different approach than this video. Instead of component usage freedom, they want API stability and ease-of-use.
Now we're creating one component for each feature rather than a bunch of them that you assemble because that follows the design system better (unlike the patterns I had at this other company). It's a 180 degree difference in component design.
The goal of TypeScript and other coding patterns is to make it dead simple to write code the intended way, so other devs can't screw it up.
1:16
This was AWESOME! thank you
any plans on doing a course or gettin back with the content? greetins from brazil ;)
I actually have quite a few videos that need to be posted and one talk about TypeScript, but I just haven't had time. I need to hire someone to manage all this.
This is great, what I don't quite get is how does the make the inside it trigger the event needed for the logic of the modal? Does it clone the child with an extra onClick prop inserted somehow?
Exactly!
Thank you very much for sharing this
Amazing Kevin 🙌
Very interesting video. But the code snippets are quite hard to follow without full code samples.
What specifically do you want to see on slides? I tried removing cruft so there's less code to read for the 2-5 seconds it's on screen. Are you wanting to see the implementation or do I need more code in the slide?
Does this help?
github.com/Sawtaytoes/children-first-components/tree/master/src
Go to Visibility or Picker stories to see uses.
@@KevinGhadyani Yeah that helps a lot! 👍 I'll dig through it and see if I can understand everything. It was hard for me to understand how the 'children-first' approach without seeing the actual implementation of all the pieces. Part of the reason is probably that I'm not super familiar with advanced React concepts yet. For me personally, especially if it's a video, I like to see complete examples, I can pause if I need some more time.
Kevin, are you going to create a course on this subject? I'm interested and don't mind helping a fellow coder by paying for a course design by you..
I appreciate it! I'd love to make a course especially with the passive income source.
Of the few courses I've tried for work, I've never gotten anything out of them, and I've never finished any either. I don't really think I'm qualified to do courses. I'd hope my RUclips videos provide enough information.
@@KevinGhadyani Bummer... A course on how to properly design components would be awesome. Anyway, do you have source code with all the examples above? I would like to look at them in order to learn more. Some of the stuff is just too vague. BTW, I'm pretty sure you are qualified. :D
I think I am fairly smart but I had to watch this twice to grasp the concept, and that is with 8 years React experience, I tried slowing it down to 0.75 speed but it makes you sound drunk... lol.
Thanks though... I am sure after a good nights rest it will make sense. I am always bemoaning counter increment examples, now I wish there was one.
Perhaps I will just try it out myself.
this is the kind of video I wanted to see when googling "advanced react patterns". I only got all those generic ass videos explaining low or medium level react concepts over and over again.
I know exactly what you mean!
great talk! 🔥
@49:37 Is sooo true 😅😅😅
Kindly write a book on this
Get me in touch with a publisher ;p
wish there was more source code for some of this
I have it linked in the description I thought. Are you looking for something else?
Link for 1 form plz?
docs.oneform.dev
I know, it doesn't show up easily in Google searches. No clue why not.
Isn't "React designed right" SolidJS in reality?
Exactly! I'm in the React world by career choice, but I've been a huge fan of Solid JS by Ryan Carniato! He had the right idea.
Am I wrong 🤔 I feel like building components like this is mostly suitable in vue than in react where one could easily register the library globally and use anywhere without having to import stuffs . Cause imagine creating a sign up form, a Modal, a drop down in a single page , you would have to import a lot of things, import this import that ooh God 🤣 this is interesting
I think it's fine. I often import a bunch of stuff. Never used Vue, but if you've seen the popular UI library Material-UI, they also make you import a bunch.
From using OneForm and these other methods, you get used to it. It makes the DOM behavior very clean.
Stop yelling at me 😅 I will fix it eventually
I would say CSS-in-JS is also a huge antipattern. The good separation of concerns here is to have an app visual language that is translated into CSS reset/sane defaults and as CSS is an exception based language, you _deviate_ from the sane defaults in your components, meaning most of your codebase the styling will be very thin. However this usually does not happen as most companies struggle with bottom-up anarchy and designers running after developers who run after business requirements.
I don't understand what you're saying.
@@KevinGhadyani Sorry man, sorry for the late reply, first of all "CSS-in-JS" not the other way around, probably I was quite tired. I think I tried telling too many things in 1 comment. When designing effective components, it's important to consider the styling. CSS is a language which provides the best results when the design follows a top-bottom approach: you define your base style, font sizes, distances, colors, then you create a limited set of containers (aka "visual language" of the site). And finally, for little details, you define exceptions from these rules. With this approach you have a very lean set of cacheable CSS rules, that is quick to download, quick to execute. If you are creating React components one must not work against this optimum.
In the second part I did a bad job explaining that most of us usually not work like this in a top-bottom approach, we are not handed a consistent design language by the company we arrive to, nor a limited set of smartly designed responsive containers, rather, we get a Figma design and we try our best, without wasting too much time on the big picture. That was the "bottom-up anarchy" thing, that because of how corporate engineering works, we usually just do what's needed to finish a task, resulting in defining the same CSS rules over and over (with TailwindCSS explicitly encouraging this behavior for example). So, we don't do the right CSS/component architecture because of how disconnected corporate teams are.
Fourty hour days?!
Back when I was working on the game, I was doing a lot of stuff all by myself, but I was a junior-level dev.
I'd sleep once every 2 days sometimes. It wasn't every day each week, but it was quite often. I remember being up for so long my vision would get blurry.
I slept when people stopped having things for me to review, but because everyone was global, I was up around the clock.
too fast speech, would be good to show more internal implementation instead a lot of slides - for ex. Providers content, show me the code
Up for 40 hours😂😂😂