13

I'm building an Angular 2 ngrx/store application and trying to understand best practices.

  • I love having an immutable state that changes only based on dispatched actions so that the app state is very clear and debug-able.
  • I love one-way data flow down from "smart" containers since this allows us to use the async pipe to do less checking of state.

But I don't understand why we would want to "bubble up" events from dumb components all the way up to smart components before dispatching an action to the store. Is the only reason to have re-usable components? It seems to me that most components aren't re-used anyways cause there aren't many situations when I would want to have everything identical including the CSS. Are there any other benefits I'm missing? From the point of view of maintainability / readability, isn't it nicer to be able to just see the action dispatched right at the component where the interaction is happening?

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265
David
  • 335
  • 4
  • 14
  • 1
    After using ng > 2 for a while, I came to realize that ngrx/effect and smart-container are two design choices you have. If you use ngrx/effects then, you don't feel too much need to use Smart-Dumb Components. – Harshal Patil May 10 '17 at 08:59

5 Answers5

11

First, I'm not an expert on the subject disclaimer.

  • I feel that smart components controlling dumb components is actually what it is called the mediator pattern. Using this pattern ensures that fewer components have to deal with the store, thus enhancing louse coupling.
  • Easy maintenance: If you have to refactor and mass rename actions it's easier to this when the action is present in fewer places.
  • Having a central place that deals with actions allows for a quick overview of the architecture. Also hot-swapping of the store access logic could be done easier.
  • And as it was already mentioned: reuse. You can share and reuse dumb components between projects that have or don't have ngrx architecture.
  • Also reuse in the same project just by wiring different inputs and outputs. Ex: A dropdownComponent could have a lot of usecases that require different inputs and outputs.
Adrian Moisa
  • 3,923
  • 7
  • 41
  • 66
7

One of the primary reasons is re-use.

In terms of MVC, think of your smart component as your controller and your dumb component as your view.

Imagine a dumb component that renders an edit form for one of your entities (model). The dumb component handles displaying the form and validation messages, however you may re-use that component on the add-entity screen, the edit-entity screen, and maybe a pop-up dialog somewhere else in the application for example. Each of these use-cases need the same form with the same validation, but you're likely performing very different actions on "submit". The smart component that invoked the dumb component is likely a different smart component in each case. By raising the event and passing the values up to the smart component you can perform vastly different actions while only coding your "view" once.

Ryan Rahlf
  • 1,772
  • 1
  • 14
  • 15
3

I totally agree with you and I have the same doubt.

I expect the component to emit an action using the dispatcher (which for ngrx/store is the store itself) instead of moving this logic to the container (the actual application).

This way the component is decoupled from the container and the container doesn't need to know about actions: it will just listen to the state change and pass down the eventual data, if necessary.

On the other hand, the Introduction to ngrx/store is promoting the design with a smarter container, which knows a lot about the underlying components.

Frankly, I can't yet see a clear winner: I just think that dispatching actions from the component is simpler, cleaner, and closer to the Elm Architecture which was one of the Redux's inspirations.

pietro909
  • 1,811
  • 1
  • 19
  • 26
  • 1
    See this article by Dan Abramov (one of the creators of Redux) https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 He states that he has now revised his approach and is happy to nest "smart" components within "dumb" components(although he is now using different names for them), citing the smartness as an implementation detail – Mark Whitfeld Aug 08 '17 at 09:24
  • 1
    thanks, actually I've read it. But in the meanwhile, I completely moved to Elm and some React Native and I was reborn :D – pietro909 Aug 08 '17 at 09:34
1

I would like expand on the given answers.

When it is said that not dispatching actions from dumb components helps re-usability, apart from allowing you to use the same component you just created again and again, it helps you integrate with 3rd party components. Those might be open-source components, or even a component that your co-worker, which is unaware of the way you manipulate data with NgRx, might develop. This way, you keep your code generic, modular, and implementation-independent as much as possible.

Just to clarify, this is all about advices, and in some cases it might be smarter to act differently, but it's usually best to stick to the conventions.

Shay Yzhakov
  • 975
  • 2
  • 13
  • 31
0

I haven't found any references about "bubble up" events to top components in ngrx/example-app. Also on Rob's talks I haven't get that (I might missed something).

I'm just using all ngrx as in example and right now it seems fine. ngrx/store to store data, ngrx/effects to chain actions (as I can simplify), and "middleware" in image of 'actions' that describing everything that you are able to do with one of the store part.

And then when it seems the most convenient I'm using action (I just making sure that all actions used in file are relevant to current class).

  • 1
    For example, in book-detail.ts, it emits the event add and remove. Then in its parent component (book-view.ts), it takes that event and dispatches an action. Why not just dispatch directly in book-detail? This case is not so bad cause it's just one level. But if you had multiple levels of components in a more complex app, I could see the "bubbling up" of output events as being pretty annoying. – David Jun 16 '16 at 19:17
  • 1
    It seems that all dumb components are something like md-input or button or the simples elements you can get. You don't want to tie down store logic to that components because if you decided to change something about your actions, reducers or effects or other store logic you will need to update every dumb component you have. If you keep all logic in 'root' components (like pages - elements display directly by router) you will have to update just few of them (easy access). So it's basically maintaining healthy app. – Piotr Grużewski Jun 16 '16 at 19:52
  • I don't agree with you @PiotrGrużewski: I think that the logic which belongs to messages' passing (and then actions) should be as hidden as possible so that containers can just focus on the actual application's logic rather than on the infrastructure. Exposing events to the container which then translates them into actions is, in my opinion, redundant. On the other hand, I think that also letting the component use directly the store is not yet a perfect solution: we might need a proper dispatcher? – pietro909 Jun 30 '16 at 07:58
  • 1
    @David: about the CSS coming with a component, I would say that it doesn't prejudice re-usability since it is common to override it. What one shouldn't modify is instead the code, that will definitely compromise the bundle. – pietro909 Jun 30 '16 at 11:37