Skip to content

This Dot Blog

This Dot provides teams with technical leaders who bring deep knowledge of the web platform. We help teams set new standards, and deliver results predictably.

Newest First
Tags:NgRx
State of Angular Ecosystem | December 2021 cover image

State of Angular Ecosystem | December 2021

This is a recap from the event State of Angular Ecosystem, you can see the full watch on State of Angular Ecosystem | Dic 2021. This event was hosted by Rob Ocel, Software Architect and Engineering Lead at This Dot. What's is new on the Angular Ecosystem? What should be expect on the upcoming releases? How Angular ecosystem looks like in the future? Also, we had this amazing panel: - Minko Gechev, Software engineer at Google, Angular Core team. - Ben Lesh, RxJS core team lead. - Mark Whitfeld, Software engineer at Stackblitz, NGXS corea team lead. - Brandon Roberts, Senior Angular Engineer, Nrwl & NgRx maintainer. - James Daniels, Developer Relations, Firebase. - Jessica Janiuk, Senior Software Engineer, Google. RxJS updates (Ben Lesh) Weeks ago was introduced RxJS 7.4, the latest version from the RxJS team, which has many features, but first of all, the bundle size compared between RxJS 6 vs RxJS 7 (if you include everything RxJS exports, included new features!) was cut by almost the half, so if you are thinking to switch between those versions, you should go ahead. Now, v7 has tons of typings fixes/updates, but now requires TypeScript 4.2+. Most of the new features included in the new version are: - Top-level exports - Multi-cast simplified - Improved retry ergonomics - Animation Frames - New tap features - AsyncIterable support That's was most of the most importants features delivered on RxJS 7.4, but there is more such as: - Ajax/fetch improvements - Supporting for aborting promises & more... Regarding in how many downloads has RxJS, the downloads has increased consideraly since RxJS 6 in 2018. Now we can 30M downloads a week, back then in 2018 they have only 10M per week. Stackblitz (Mark Whitfeld) Now Stackbliz has support for Angular v13, this was thanks to the upgrade of Stackblitz v2, which runs over web-containers. This new upgrade to Stackblitz v2, avoid to have custom-code depending on which framework you are running, making Stackblitz more agnostic from the framework (Angular, React, Vue) you are using. In fact, there is no custom-code to support any of the most used frameworks. NGXS (Mark Whitfeld) Now NGXS has support for Angular v13, with this mayor release there are up-to-date with the latest version of Angular. They are working on deliver another big features too. Angular Core (Minko Gechev, Jessica Janiuk) Ivy Ivy now its the default engine to run compilation in Angular, which lead us a huge increase of performance vs versions who runs other engines to compile Angular. With the implementation of Ivy as default, we can see a: - 90% reduction of computational resources. - -50 mins faster build for the biggest app in Google. - Improved debuggability and profiling. - More effective relation between Github issues vs Fixes, thanks to a huge effort from the Team. - New system for RFC process. What's new in Angular v13? With the recent release of Angular v13 some new features are delivered, which include: - Removal of IE11 support (no more polyfills file, yaaaay) - Modern angular package format. - Partially compiled Angular - Removed UMD bundles - ES2020 output - Adobe font inlining - Webpack 5 cache - Dinamic validator control - Better a11y What are we building next? Some of the upcoming improvements are: - Extended analysis - Simplified factory API - Advanced guides - MDC Web Standalone components Maybe some of the biggest updates which are upcoming on the next versions of Angular are Standalone components, who will run without adding to any module. This Standalone component will be bootstrapped directly into the Angular module, and the bundle will be reduced significantly. NgRx (Brandon Roberts) The most recent version of NgRx added some new features as: - Angular v13 support - RxJS 7 support - Ivy compiled libraries support - Feature creators - Improved selectors - Contributors page Nx (Brandon Roberts) The recent release of Nx, which is v13.2, also now include Angular v13 support. Also NgRx v13, and NestJS 8 support was included in the most recen version. Now, there is a RxJS 7 upgrade option for Nx. AngularFire (James Daniels) The official library from Firebase to Angular also release some of the next features: - Firebase v9 support, entirely tree-shakable support, RxJS 7 & Angular v13 support. - Firebase v8 compatibility. - Internally uses AngularFire, increased agility and less duplication. - Partial compilation, Ivy support. - Powerful new schematics In the upcoming releases for AngularFire, the team is working to improve the next items: - Documentation drive - ng deploy capabilities - More schematics on the way... - Better bundling/rehydration - Prebuilt UI components Conclusion Angular v13 bring to us so many new features, therefore the Ecosystem of Angular is updating to support this new release. Some of the most libraries used with Angular are pushing forward and taking the framework from Google to the next level. Also the Angular team, is listening to the community and making the upcoming releases more beginner-friendly such as `Standalone components. As Angular dev, we celebrate the removal of IE11 support without that, we can take advantages of most CSS features who are not supported in that browser....

Advanced NgRx: Building a Reusable Feature Store cover image

Advanced NgRx: Building a Reusable Feature Store

Advanced NgRx: Building a Reusable Feature Store As an angular application grows in scale and complexity, so often is the need for state management to help simplify its many moving parts. What often occurs is an increase in the amount of boilerplate involved in managing many feature states, and stores. Increase in store size can often lead to repetitive patterns, much like in poor component design. However, if state is written well, an application can utilize a less common pattern- a reusable feature store- as we attempt to eliminate much of this boilerplate headache. The following proposes a pattern where we’ll create a pattern for properly consolidating several stores, gain consistency across similar features with a reusable store, and address any pitfalls in this pattern. When to use consolidating state management patterns Before we get too deep into consolidating, we should first stop, and assess, when and why we're attempting this task. Why consolidate in the first place? - Reduce repeating patterns in feature design. - Increased maintainability of similar features. - Quicker iterations. - A better shared abstracted layer that can be extended as needed for edge cases. - Similar or extensible UI or data stores. When should you consider consolidating? A hard to answer question, but one that's satisfied by having really good foresight, a roadmap of how an app's features will work, or a set of existing features that may need a few iterations to bring them closer in overall design. What this means for both approaches is that a feature can be initially designed similarly to another, or be made to function similar to another to make it _DRY-er_ (Don't Repeat Yourself) later on. A closer look at the store pattern Now that there's a direction and reason for our efforts, let's look at the pattern using a mock version of photo website - Unsplash - to build out a data store. Let's say we have several states that look like this: ` Fortunately for us, our photo assets follow a very similar pattern. This state is simple as it will contain photos in a simple state. However, we can squash these into one state like this: ` And with that simple bit of code, we've opened up the possibility to reuse a data store per photo type into a single store! For example, a website like Unsplash could use several strategies to fetch and display photos like filtering by photo type on navigation, or pre-fetching chunks of photo types in a resolver. Imagine if each photo type acted as an individual store? That would be a lot of stores to maintain! Building the new state and reducer As this new feature store is built, keep in mind that typings become tricky when you begin to use an indexed interface as a type. Typing pitfalls Typescript doesn't like when we add more properties onto indexed interfaces because it assumes that we'd only be adding properties that follow the initial type we assigned to the index property. In this case Photo[]. For example, this will work: ` But this won't, because PhotoType on selectedPhotoType doesn't overlap in types: ` To overcome this, we can use an Intersection Type like so: ` Defining the reusable part of state We want some amount of flexibility in our store, but we have to tell the new store what features we intend to keep similar in pattern. One way we could do this is by creating a dictionary of features. Building the initial state for the photo types could look like: ` And initial state for the reducer: ` Another win for reusable store pattern Maybe you noticed already, but what if each of the individual states used entities? We could help ourselves, and speed up our dev time some more with the adapter methods and selectors exposed per PhotoType. Our biggest win here comes from the fact that we can still use NgRx Entities even in these seemingly nested states of state. The above piece changes like so: ` And give the state slices an initial state: ` Tying it together with the reducer and selectors Now that we have the state accurately defined. We can access the select slices of our single store using the selectedPhotoType property: ` And for the selectors: ` Again, we can use the entity adapter and leverage entity methods and selectors. Full Code Example Here. Conclusion When working with state management stores in NgRx, it shouldn't be a mess of maintaining boilerplates and changes that affect several data sources with the same store shape. As developers, we want to think of future-proofing strategies that abstract enough, yet still help us understand exactly how the application works. By leveraging a reusable store strategy, we gain consistency with like features, a level of abstraction and sharability between like features, with the ability to extend for edge cases, and easier maintenance....

Working with NgRx Effects cover image

Working with NgRx Effects

Working with NgRx Effects Almost every web application will, at some point, need to interact with some external resources. The most classic solution to that would be a service-based approach where components are calling and interacting with the external resources directly through services. In this case, most of the heavy lifting is delegated to the services and a component in this scenario still carries a responsibility to directly initiate those interactions. NgRx Effects provides us with a way to isolate interactions, with the aforementioned services, from the components. Within Effects, we can manage various tasks ie. communication with the API, long-running tasks, and practically every other external interaction. In this scenario, the component doesn't need to know about these interactions at all. Its only requires some input data and then emits simple events (actions). In this article, we will build on top of the application we started in Introduction to NgRx. You can find the entry point for this article on my GitHub repo. If you want to follow this article's code, please clone the repository and checkout the effects_entryPoint tag. ` After cloning, just install all the dependencies. ` and you can see the example app by running ` Getting started In order to add NgRx Effects to our application, all we need to do is use the ng add functionality offered by the Angular CLI. Run the following command: ` It will add and install the @ngrx/effects library to your package.json and scaffold your AppModule to import the NgRx EffectsModule into your application. This is the code that the Angular CLI will generate for you: ` With the setup complete, we can start modifying the app to introduce and handle some API calls using Effects. Design interactions - Actions & Reducers When you're designing new features, I highly encouarge you to first create the actions which we expect to see in the application. Let's look at the example API, which you can clone and checkout: effects_ready branch from this repo. Then, use the npm start command to run it locally. The API consists of the following endpoints: GET /api/photos - returns an array of photos PUT /api/photos/:photoId/like - returns the photo that was liked PUT /api/photos/:photoId/dislike - returns photo that was disliked We can start designing our app interactions by handling how the list of photos is loaded. First, we'll need a trigger action to start fetching the list of photos. Since the request can either return successfully, or with an error, let's model that as well within the actions: ` We have modeled the actions that might occur in the application. Now it's time to handle them properly in the photo.reducer.ts. ` Since we're getting an array of photos, and we're keeping them in the state as an id-indexed map, we just need to transform it into the appropriate shape. Since we assume that the API returns all of the photos, we can replace the whole previous state. Great! We now have a correctly working reducer. However, we don't actually emit any action that will put the data in our Store anywhere in our application. To verify that it works correctly, we can dispatch loadPhotosSuccess action in our AppComponent: ` The data is loaded correctly and all the other functionality is still working as expected. Let's revert this dispatch so we can finally create our Effects, which will allow our available photos to asynchronously load. Create Effects In NgRx, Effects are encapsulated in a regular Angular Injectable class. To let NgRx know to use our class as Effects, we need to add an EffectsModule.forRoot([]) array inside of our AppModule imports: ` ` Inside of the PhotoEffects, we will create properties that will react to specific actions being dispatched, perform some side effect (in this case an API call), and susequently dispatch another action based on the API call result. This flow is presented in the following diagram: In our case, we will listen for the loadPhotos action being dispatched. Then, we will call the PhotoService -> getPhotos() method, which should either return the correct data, or return an error (ie. a network error). Upon receiving data, we can dispatch the loadPhotosSuccess action, and in order to handle possible errors, we might dispatch loadPhotosError: ` The app still doesn't do anything. That's because we need the loadPhotos action to be dispatched somewhere. We can do it on the AppComponent initialization inside of ngOnInit lifecycle hook. ` If we look at our application again, we can see that the correct data has loaded. In the network tab of the Dev Tools, we can see the correct API being called. Liking/disliking still works, at least until we refresh the page. We still don't perform any API calls when we like or dislike a photo. Let's implement that behavior similarly to how we implemented photo loading. The easiest way to accomplish this is by treating the likePhotoand dislikePhoto actions as triggers for the API call, and upon a successful or failed response, emitting a new action. Let's name those updatePhotoSuccess and updatePhotoError: ` Now, in reducer, instead of having separate handling for like and dislike, we can replace it with a single handler for updatePhotoSuccess ` Now, with all actions and reducers in place, all that is left to do is add a new effect responsible for performing API call and emitting a new action for updating the state. ` Conclusion Now, all the functionality is still working, and our data is kept safely on the server. All of this was done without modifying the component's code (except for initial dispatch of loadPhotos). That means we can add some complex logic for how we handle data (ie. add data polling, optimistic update, caching etc.) without requiring the components to know about this. This enables us to keep the codebase cleaner and much easier to maintain. You can find the code for this article's end result on my GitHub repos: * Angular app * Photos API app Checkout effects_ready tag to get the up-to-date and ready-to-run solution. In case you have any questions you can always tweet or DM me @ktrz. I'm always happy to help!...

Strong Typing the State and Actions in NgRx cover image

Strong Typing the State and Actions in NgRx

Strong Typing the State and Actions When working with NgRx store, it is highly recommended to provide strong and explicit types for both the State and Actions. This becomes even more significant as our application will inevitably grow, which means it will need more features and almost certainly some refactoring along the way. This is where strong types might make this process easier and safe. I'll base this article on a simple Angular app where we can display a list of photos that then can be liked or disliked. You can find the source code of this application on my GitHub repo. If you want to follow this article's code, please clone the repository and checkout strongTypingState_entryPoint tag. `` git clone git@github.com:ktrz/introduction-to-ngrx.git git checkout strongTypingState_entryPoint `` After cloning, install all the dependencies: `` yarn install `` You can see the example app by running: `` yarn start -o `` Typing Actions With the latest version of NgRx, typing actions is very straight forward. Quoting the docs: > The createAction function returns a function, that when called returns an object in the shape of the Action interface. The props method is used to define any additional metadata needed for the handling of the action. Action creators provide a consistent, type-safe way to construct an action that is being dispatched. Creating actions for liking and disliking a photo could look like this: ` This creates concise and type-safe actions and action creators all-in-one. It also doesn't produce as much boilerplate as the class approach, which was used in previous versions of NgRx (and can still be found in many production code repositories): ` In this example, we need to create classes for each action that act as action creators. However, it is good practice to extract all possible action types into an enum or a set of consts and a separate type union PhotoActions to use later ie. in reducers. All this behavior is neatly packed into the createAction utility function so for creating new actions, I highly suggest using it. Typing State When it comes to typing state, it's a good practice to type every slice of the state containing a specific feature separately. A good place to include it is a reducer file which will handle this specific slice of the state. For larger projects, you can also keep your state types in a separate file ie. src/app/store/photo.state.ts ` Typing rest of NgRx chain (implicitly) By having both State and Actions strongly typed, all created reducers, selectors, and effects can easily infer further types and keep the rest of our NgRx chain type-safe. ` By providing initialState to createReducer utility function, our photoReducer is strongly typed to operate only on PhotoState type. Each on(...) call uses a TypeScript type inference from the provided action (likePhoto, dislikePhoto) so that ` is actually strongly typed as ` The same rules apply to building selectors from our state ` By providing strong explicit typings for selectPhotoFeature, TypeScript will usually be able to infer types for all the other selectors derived from it. When creating a new derived selector: ` it is equivalent to explicitly typing everything like so ` Not everything use case can be inferred automatically but usually, a small hint for a TS compiler is enough ` state param can't be automatically inferred and has any type by default. Angular will complain about it in a strict mode, so in order to complete the typing, we can explicitly add the proper PhotoState type here. ` Benefits In conclusion, by providing strong typing for just Actions and State, we get typings in other parts of NgRx chain usually for free (or by providing minimal hints for the TS compiler). This means that we can benefit both from our IDE auto completion when writing the code. It also provides us with a safety net in case of doing some refactoring or adding new functionality to the state. For example, if we modify the shape of the state in order to accommodate for a new feature, we will immediately be notified by the TS compiler or our IDE of which other parts of the app chain are affected. This way we can review all of them more easily. When combining that with a high test coverage, we can have a good level of confidence to modify the code without breaking anything in the process. You can find the code for this article's end result on my GitHub repo. Checkout strongTypingState_ready tag to get the up-to-date and ready-to-run solution. If you have any questions, you can always tweet or DM me @ktrz. I'm always happy to help!...

Developer Tools & Debugging in NgRx cover image

Developer Tools & Debugging in NgRx

Developer Tools & Debugging in NgRx When working on a complex software solution, we often find ourselves scratching our heads over a bug that was reported to us. It's essential to have proper tools to trace the issues which like to hide in our code execution paths. Luckily for the devs using NgRx in their project, the application state is kept in a single location and all the actions that can modify it are easily traceable with some great DevTools. As NgRx adheres to the redux pattern, we can use the same Redux DevTools as we would use for any other Redux base application. This tool is essential for me when debugging an NgRx based application. If you haven't worked with NgRx yet, I recommend reading this post first where I introduced the NgRx pattern into a simple app. Getting started In order to make our NgRx store visible in the Redux DevTools, we need to pull in a module provided by NgRx platform - @ngrx/store-devtools. For the installation instructions, please visit the official installation guide. After installing the Store Devtools using the AngularCLI schematics, the following code is automatically added to our AppModule: ` maxAge property is limited to 25 by default for performance reasons - this is the limit of actions stored in the history tree. logOnly is usually set to true on production build to limit the number of features used when connecting to Redux DevTools. I suggest adding name property to our initial configuration to more easily find our state in the DevTools (as it will show all the other stores which might be used in other tabs open in the browser). ` With that minimal setup, we can already start using the Redux DevTools to start debugging our application. You can access the Redux DevTools in the Redux tab on your browser developers tools. Tracking actions The first thing you can do in the Redux DevTools is track all the actions that have been dispatched within the application. For every selected action, you can see the current state value, what exactly has changed in the state as a result of this action, and the content of action object. Moreover, the extension gives you the possibility to "time travel" your application and skip some of the actions to see how it would affect the end result of the state. You can either manually select the point in time to jump to or replay the whole sequence of action using timeline at the bottom. Those functionalities alone provide us with handful of possibilities on tracking how the state of our app is changing over time and pinpointing the possible issues. Replicating the app behavior Another very powerful feature of the Redux DevTools is tha posibility to dispatch the actions without the need of interacting with the UI. It's available as one of the tabs in the bottom extension's menu: By using this feature, we can dispatch any action we want. This is extremely useful if we find the exact course of actions that is leading to an error, but it's hard or long to replicate using the UI. We can enter and dispatch the desired sequence of actions and get to the troublesome point in the app state with ease and in a reproducible manner. There are a few features that combine well with the aforementioned dispatching technique: - Persisting the state - Commiting and reverting the state When we select the persist option, the extension makes sure that our state is persisted and restored even after we reload the page. The commit option allows us to store the state at the specific point in time and treat it as a starting point (it's like saving the game before going on to fight with the boss 🤓). You can perform as many actions as you want from this point on, but you'll always be able to restore the state to a point in time at which you've done a last commit. The restore functionality is only available in the log monitor and not the inspector. This plays really well with dispatching actions directly from the extension. We can test and debug how our application behaves (ie. via Effects) when dipatching a specific action with always exactly the same comitted state. Also, it's easy to repeat by reverting the state and dispatching the action again. NgRx Store Dev Tools options So far we've covered many use-cases of the Redux DevTools, but we can configure it's behavior to our needs when setting up the StoreDevtoolsModule. In real life applications, our action log might consist of hundreds of actions which might pollute our view of what is happening in the app. We can filter them out directly in the extension but that doesn't solve the issue of the limit on number of actions visible at once. We're still limited by whatever the limit we set, and for performance reasons, we should not take this limit off or set it too high. For debugging purposes, we might only be interested in certain type of actions or definitely know that some actions (ie. the one dispatched by Angular Router) might not be useful to us at the given moment. When setting up our StoreDevtoolsModule we're given 3 ways to filter the actions that will be sent to the Redux DevTools extension: - actionBlocklist - actionSafelist - predicate The first two are the most common ones to use. We can either block specific patters of actions (which we know that are not of interest to us) or we can allow only certain types of actions. Both of them take an array of strings as a value and act as a regex on action type property to filter out only the ones we're interested in. If we want to do more specific filtering, we can use predicate. It takes current state and action as parameters and is called for each dispatched action. To allow action to be passed to the Redux DevTools extension, it must return true. With those techniques, we can narrow the scope of actions visible in the extension and therefore make it easier to get the grasp of what is happening in the app. Conclusion With the tools and techniques mentioned above, you should be able to debug your NgRx based application with a bit more ease. It's important to know the tools you have available so that you can use them when the need arises. In case you have any questions you can always tweet or DM at me @ktrz. I'm always happy to help!...

Introduction to NgRx cover image

Introduction to NgRx

Introduction to NgRx Why Angular projects are getting more and more complex these days. With handling all the user interaction, application state and accessing this state in every place, it might be necessary but quickly become over complicated. This is why having a one, global app-wide state management system that can be accessible throughout the application may be very useful in modern frontend application. One of the solutions available for Angular applications is NgRx. What In this post, I will give you a quick introduction on how to get started using NgRx in you Angular application. I'll base this intro on a simple Angular app where we can display a photo which then can be liked or disliked. You can find the entry point for this application on my GitHub repo. If you want to follow this article's code, please clone the repository and checkout entry_point tag. ` After cloning just install all the dependencies ` and you can see the example app by running ` We will convert this application to use the NgRx state management in just few steps. How Key concepts Let's start with introducing a few key concepts and building blocks of NgRx. NgRx is a state management tool inspired by Redux, so the building blocks might be familiar to Redux users. To build and operate on our state, we will need the following basic building blocks: - Store is where state of the application will be stored. It's both an Observable of a state and an Observer of action. - Actions describe all the possible and unique events that can occur within the application. They can occur ie. by user interaction, communication with the server or can be a result of other actions. - Reducers are what binds the actions and the state. All the state changes must occur as result of an action. Those changes are handled by pure functions called reducers. They take the current state and the latest action and compute new state value based on that. - Selectors - to retrieve part of the state that we're interested in, we use pure functions which extract the portion of the state that a given component might be interested in. NgRx flow NgRx makes sure that all the interactions in the application follow a certain unidirectional flow. The following diagram illustrates the general flow of the state: Getting started The easiest way to add NgRx to the project and get started is to use a Angular CLI schematic. ``sh ng add @ngrx/store@latest `` This command will - add the @ngrx/store package to package.json -> dependencies - yarn install or npm install those dependencies - import the StoreModule.forRoot({}, {}) in your AppModule Define Actions The first thing to do after installing the necessary dependencies is to define some actions that can occur in our application. In our case, this can define the following action: - like photo - dislike photo To put that into code, let's create the following file: src/app/store/photo.actions.ts ` In this file, we define all the actions (action creators) that can occur in our app. In general, the shape of the action has to be in the following share: ` The required part is the type property which will be used to identify our action. Other properties are optional and might be used to pass some additional data associated with the event ie. id of the liked/disliked photo. What we've just defined are action creators. They are functions which return an action of a specific type. To create ie. like action we can do it as following: ` Define Reducer Now that we have our actions defined, we need a way to consume them and thus make actual changes to the store's state. As described before, this is done using pure functions called reducers. We could define the functions from scratch using ie. switch case statements, but NgRx comes with some handy helper functions which make this process much nicer. Let's create a file to keep our photo reducer in: src/app/store/photo.reducer.ts ` As you can see, you import the actions which we've defined previously and use them in our reducer. createReducer is an utility function which creates a reducer with a provided initial state. This gives us a nice quick way to define new reducers as well as great type inference. TypeScript knows the shape of state that photoReducer operates on from the shape of initialState object. on(...) function can be considered as case statements within a switch. We define that if we encounter a given action, we produce a new state derived from its previous value and optional properties provided within the action. All this code could be rewritten in the following shape. In my opinion, the construction mentioned above is both more consise and self explanatory as well, so I suggest using it. ` After creating a reducer, we need to let our application know that we want to use it. We can define it in our AppModule file and add it to the properties of the StoreModule.forRoot's first param. ` Define Selectors Now that we've defined both possible actions and reducer to handle them, we need a way to get the data from the store. To do this, we'll create another pure function called selectors. The responsibility of selectors is to transform the whole state object (which can we a really large object in real life examples) into small bits necessary for a specific part of the application. In our case, we need a way to get the photo information along with the number of likes/dislikes that it currently has. Let's create another file in our src/app/store directory src/app/store/photo.selectors.ts ` We are again using the utility function provided with NgRx - createSelector. Because our state can be a nested tree of objects, this enables us to create more complex selectors based on the already existing ones. In this case, we combine selecting a photo slice of our whole state with selection of the whole photo object (in this case most of its props are static). Whenever a number of likes change, we will get a new instance of the photo, which makes detection of changes super easy and performant. Use all the building blocks in our component Now that we've defined all the necessary building blocks, we can finally start using them in our AppComponent. The first thing we need to do is inject the Store service into our component. ` This gives us access to both selecting data from the store (as an Observable) and notifying it about actions happening (by dispatching actions). Now let's select the state of the photo into a component's property and define methods for dispatching like and dislike actions. ` To select data from store, we can basically treat it as an Observable and use pipe operator on it. To select data with our previously created selectors, we can use select operator provided by @ngrx/store package. To dispatch actions and notify the store of it, we can use dispatch() method and feed it with the necessary action (also defined above). Now all that is left to do is hook up all this state and methods into our component's template. ` As you can see, we use async pipe to unwrap the photo$ observable and pass a plain object into the [photo] input. The app-photo component provides two outputs: like and dislike which we can react to with our AppComponent's methods. For clarity purposes, let's define our PhotoComponent in src/app/photo/photo.component.ts (It's already defined within the entry point repo but needs some minor tweaks.) ` and PhotoModule in src/app/photo/photo.module.ts ` Now start your application again and see the result it the browser. You can still like/dislike the photo and the state of the app is stored withing NgRx store. Conclusion As you can see, setting up this example required a bit more code to start with. But when the application grows, this additional code pays off as we get one central place where all the state changes are happening. We can see exactly what actions are being dispatched (ie. by using Redux Devtools) and therefore our application is more maintainable. In case you have any questions you can always tweet or DM at me @ktrz. I'm always happy to help! More articles are coming soon! Do not miss any of them and visit the This Dot Blog to be up-to-date....

NgRx Facade Pattern cover image

NgRx Facade Pattern

The NgRx Facade Pattern was first introduced by Thomas Burleson in 2018 and has gained much discussion in recent years. In this article, we will discuss the pattern, how to implement it in Angular and discuss whether or not we should implement it....

Modular Multi Step Form with NgRx in less than 20 minutes cover image

Modular Multi Step Form with NgRx in less than 20 minutes

This is the third part of the ReactiveForm series. Now that you know how to use ReactiveForms and techniques to make it accessible, it's time to do the real thing....