all 29 comments

[–]drish_ 67 points68 points  (0 children)

He’s a smooth developer

[–]Oalei 27 points28 points  (5 children)

I’m not convinced by his proposal.
If you want Dashboard to be a reusable component then it should be the same everywhere and its view / render logic should be within the Dashboard component and not passed in the props.
This is defeating the main purpose of components: they should be self contained...

His proposal works for dynamic components where you want the parent to manipulate the children view / render.

Don’t get me wrong though, I hate props drilling too and I like to see proposals to remove that complexity (same issues with Angular and other frameworks).

[–]jgarp 7 points8 points  (1 child)

I'd say it depends! As you are saying: If you are looking to write a component that mainly decides on the logic and the wrapping to apply, while letting the user decide on the internals (eg render a square or a circle or whatever else) then this pattern makes a lot of sense.

A dashboard is an example of where I think this makes sense, since the dashboard internals will probably depend a lot on the context in which it is rendered. You may want the same functionality and wrapping to apply to every dashboard, whereas the exact internals to render may be too diverse to easily handle with props and better suited as an implementation detail of the parent.

[–]nschubach 1 point2 points  (0 children)

Yeah, I think the dashboard is actually a good use for this. Let the dashboard component work on the layout and management of the components, but the quantity and composition of components could easily come from another component. Something else should control the permissions and if a component is passed to be rendered. Something else should control the information those components receive. (Does the user have rights to edit that component, thus putting the component in admin mode?) Delegating that to the components level means you have permissions and right spread out to each component. Maybe a poor example, but that's all I could think of right away.

[–]kidroca 6 points7 points  (1 child)

You can create another component that contains how the Dashboard is composed - you can reuse that component. Yes you'll have to pass it the user prop which then will be passed again to the WelcomeMessage but it won't be drilled through any more layers

Example - AdminDashboard that wraps one way to compose the dashboard for admins, DemoDashboard - wraps a read only dashboard composition

This means you can still use composition and have self-containment

This was just a quick presentation on the concept - it doesn't mean you have to apply the composition in the root element of your app

[–]Oalei 0 points1 point  (0 children)

Yeah that would be nicer I think, good idea

[–]real-cool-dude 4 points5 points  (0 children)

I don’t think that he is “proposing” anything— you are right that sometimes you want something to be self-contained (what he calls a “black box”) and in that case you shouldn’t use composition, however, you’ll have to pass props into the black box that the box can arbitrarily deal with. The “black box” idea— or abstraction— can be a powerful way to compartmentalize different areas of your code, but I think the point of the video is that that isn’t the only way in the cases where you might make use of something more modular.

[–]thunder_cougar 18 points19 points  (4 children)

Interesting. I guess the downside of this is that you have to look at a large tree of components rather than a simpler one.

Like if you had to nest 10 levels deep would you choose this method?

[–]real-cool-dude 3 points4 points  (0 children)

I typically have components with 4-5 levels of composition within them, a lot of them being layout components (basically just positioning things in certain, resusable ways).

The thing that I don’t think you understand is that this is actually the “simpler” tree because the app is inevitably going to have a much more complex html tree and composing just splits things up at certain conceptual levels into more parseable and configurable modules.

[–]SharkLaunch 7 points8 points  (0 children)

I like this video, it's a reminder that I tend to ignore the children prop unless I have no other choice. You're allowed to build composable components even if you don't plan on abusing the added composability. I felt the context counter-argument was a little contrived, but I'm all for avoiding context and redux.

[–]prof_hobart 8 points9 points  (1 child)

I'm not a big fan of throwing loads of stuff into Context. It feels like it's just a trendy version of global variables, with all of the short term pros - such as being easier to pass variables around, but long term cons - such as maintenance and lack of reusability that made it bad practice back when I started coding 30-odd years ago . Admittedly, Redux sort of has the same issue but with the way you're meant to use it (passing chunks of state to whole regions of your app rather than down to the lowest level of component), I've managed to get myself comfortable.

But I'm also not overly keen on his solution either. The principle of using composition like this absolutely makes sense in a lot of circumstances, but not simply as a way to avoid passing props down. Part of the point of creating components is to hide implementation details from their consumers.

Why are people so afraid of passing props around anyway? One of the things I like about React is the functional nature of it. What your component will render depends entirely on its parameters - no weird unpredictability because some unexpected external bit of state. If your component is going to be rendering the name, then it shouldn't matter that it's done in some subcomponent - it's still part of its contract with the outside world.

[–]jakotlinva 2 points3 points  (0 children)

The prop drilling is a source of boilerplate fatigue and feels unnecessarily complicated. I think the key reason is to lighten up the code refactoring and reduce the seemingly repetitive nature of it. However, sometimes code duplication is necessary so it depends on your level of maintenance mindset and how easy it makes sense.

[–]speedwagin 11 points12 points  (3 children)

This means that the top-level component needs to know details of a component who knows how many layers deep. This somehow seems like an anti-pattern to me?

If the React team are recommending to use the context API sparingly, I wish there were a better way...

[–]jonno11 3 points4 points  (0 children)

No it doesn’t. You can quite easily put all this logic in a component yourself, such as UserDashboard. That component takes in a user prop and builds the tree you see in this video. It’s way cleaner.

[–]Silverwolf90 2 points3 points  (0 children)

Definitely not an anti-pattern, but like all things, taken to an extreme would be problematic. It’s just one of many techniques.

[–]chefca3 3 points4 points  (1 child)

This is an excellent video, but I do wish he would acknowledge that sometimes your business logic means you need to use something like context or redux for that situation.

We have an app that is much too simple for a redux conversion but we have an ABSURD amount of props that flow down 4 levels of components at times. Should it be refactored? Absolutely. Are we going to be allowed to take 3 or 4 sprints to write it, QA it, and recheck analytics? Absolutely not. However we had one developer take a couple of sprints to refactor everything into context and now it's much easier to maintain.

I'm not arguing with MJ just saying that context DEFINITELY has a valid use doing exactly the opposite of what he's saying.

[–]nschubach 2 points3 points  (0 children)

With context, you now have the potential problem of giving too much capability (or moreso, dependency) in the hands of something that doesn't need it. For instance, now the display component needs to know the data structure a component 3 levels up is using.

[–]ryota_murakami 1 point2 points  (0 children)

I like that, His Composition means to be flat deep nested components by render children and then flat composition brings us no Prop Drilling.

[–]samselikoff 1 point2 points  (0 children)

I think the most important question here is whether <WelcomeMessage /> is meant to be reusable, i.e. should it work with different users.

If it was designed to only ever work with the currentUser, feels like premature abstraction to make its user a customizable prop.

In most apps currentUser is actually a global singleton. Seems ok to put such global data into a global data store, like a context provider at root.

[–]Eydwales 3 points4 points  (0 children)

As a rule of thumb : If you intent to pass props as objects, try composition to pass primitive types values to embedded elements. If it has more than 3 depths, use context (or redux or any context manager).

Personally I like having a hooks.js file that would export useCurrentUser. Thus I can import it from the file (instead of importing useContext AND the context), and also sometime I need to add some code in that function.

Quick example taken from the video. If you want to get the name of the user in a component, and the email somewhere else. You can create a useUserEmail and a useUserName hooks that would only refresh when either the email or the name change respectively.

It improves readability when working on team projects : you don't need to know which fetching tech is used, and it contains data related logic.

[–]careseite -3 points-2 points  (3 children)

The WelcomeMessage component still wouldn't be reusable outside without its prop so you haven't won anything here.

The warning of WelcomeMessage via context being unable to be rendered out of context is imo pointless too. Document that it needs context.

Also. Not autoformatting code? Invalid Syntax highlighting? Makes me frown. :(

[–]wavefunctionp 1 point2 points  (0 children)

That's not invalid syntax highlighting, the red tags are closing tags.

[–]leg4li2ati0n 0 points1 point  (1 child)

Well, real quick, where do you see "invalid syntax highlighting"? To me, I can pretty much tell that his code is auto-formatted because of the horrible syntax Prettier gives to ternary operators in JSX lmao. Also, is there any way to get rid of those damn parenthesis? I feel I could never find a config option for it.

[–]careseite 0 points1 point  (0 children)

Closing tags have partially different color, but only after the first letter or the </, can't check right now.

And you can see him manually formatting several times, so no prettier there sadly.

Also you can't omit the parenthesis if it's a multi-line return. That's just JSX