Briebug Blog

Sharing our thoughts with the community

I’m not ready for NgRx


Angular has come a long way since I started using it back in 2013. The days of “$scope” and massive views/controllers have been replaced with component-based architectures and more elegant patterns. One of the more popular patterns over the past year or so is NgRx. For every supporter of NgRx, there seems to be one in complete disagreement and another that doesn’t care. I hear a lot of chatter about whether or not a project really needs NgRx, and I’m going to say that if you’re not sure, then you probably don’t need it.


But, what if your project grows and one day needs a little more structure? One day you might want to implement NgRx into your project as the complexity grows, so a good strategy upfront could save you from a massive rewrite later.


One alternative solution that gets thrown around a bit is service with a subject, but after scouring the web, it can be tough to find good examples of how to implement it. The first question that comes to mind is, “if this is such a good solution, why aren’t more people talking about it”? I asked this question myself and starting digging around to find out what all the hype is about.


Service with a subject is a simple pattern that when applied correctly gives developers a clear path to upgrading to NgRx (or similar redux pattern) with little to no refactor necessary. The basic premise is that each service will have a public behavior subject that will get set to the observable stream returned by our service calls.

Service with a Subject Example Code



The biggest change here is when you call the user’s service “getAll function”, you no longer get a reference to the observable returned by the HTTP call. Instead, the behavior subject (an observable stream) gets a new value-added to the stream. This allows multiple components to share the same data and not be concerned with how the data is being updated. We protect the behavior subject by making it private and exposing a read-only property that returns just the observable stream and prevents others from tampering with the stream directly.


Why do we use a behavior subject? Why not a regular subject? This is a great question and may not be obvious to everyone. If we used a regular subject class, it would still function almost exactly the same, but we may begin to notice how some components get the updated data where others don’t. This is because a regular subject will return values since you subscribed, but doesn’t hold onto the last value. Behavior subjects can have an initial value and return the last value, regardless of when subscribed to.


So now that you understand the basic premise of what service with a subject is about, we are ready to see how it all gets implemented.


If you’re not already using the container/presenter pattern, it’s one of the core patterns for modern web development. It doesn’t matter if you call it smart and dumb components or container and presenter components; it’s the same exact concept. If you aren’t familiar, I’ll be writing an article on it in the coming days.


The quick overview is that container components are typically your top-level pages (not always) that are concerned with how things work. They are responsible for loading data, passing it to children components, and handling events as they bubble back up. Presentation components are just concerned with making the page look pretty. They receive data from a parent without knowledge of where it comes from, display that data, and emit events up to the parent for all user and system interactions. Presentation components have no business logic so that they can maximize reusability.


The container component will be responsible for calling the user service to get the data. In the example below, the “user$” variable is an observable stream of user objects that is set to our user service behavior subject. Anytime the behavior subject receives a new value, the container component will also receive that value without needing to be notified. On the initialization of the container component, the user service “getAll” method is called and the behavior subject will get a new value when the call completes.



The container component passes the data to the presentation component using the async pipe as illustrated in the example below. By using the async pipe, there is no need for a subscription to the observable stream. The presentation component will re-render when the stream receives a new value automatically and without expensive change detection.



The presentation component receives the data as an array of user objects and has no knowledge of the observable stream or how the data was obtained. Because the data received is from the container component is always new data and immutable, the change detection strategy can be set to “onPush” and gain the performance benefits.



As you can see, the service with a subject pattern is very simple. Our controller components can request data on initialization and share that data with child presentation components via the async pipe. If an event causes the data to be updated, all of the presentation components will automatically be updated and without paying the price of change detection. You will also reap the benefits of using the container/presenter pattern to create components void of heavy business logic, simple to test, and maximize their reusability.


If you want to update this component to use NgRx, you have two simple options. You can replace the service calls with calls to the store or you can apply the facade pattern for the service to make calls to the store. My friend Thomas Burleson wrote a great article on the topic. If you choose to use the facade pattern it would allow you to upgrade to NgRx without having to make modifications to your components.


Check out this sample repo for a fully working version here.



Thanks to Phil Feinstein.


Author: Jesse Sanders, CEO & Principal Architect

View Details
- +
Sold Out