Creating query param synchronization with Redux

Share on facebook
Share on google
Share on twitter
Share on linkedin

Dealing with query params can be some muddy stuff. Done wrong it can be just as ugly as caching logic that is bloating your code base. The way to handle such cross-cutting concerns is using aspect-oriented programming.

Nice namedrop smart ass, what does this mean?

Well, it means that you are coding in a way that allows for separation of cross-cutting concerns, such as eg. caching, logging and… wait for it… query param handling, which is what we will be working with today. In normal words, aspect-oriented programming allows for extending the codebase without actually modifying the code itself. This is done by hooking into specific events in the framework and trigger the desired logic on these events, eg. update query params when some Redux store property changes and update Redux store property when query param changes.

This is how we will implement query param handling by creating automatic synchronization between query param values and a corresponding property in the Redux store.

Using query params vs route params

When passing data from the URL to the app, there are two ways to do it: with query params and route params. Query params are what comes after the “?” in the URL and are key-value pairs separated with “&”. Routes, on the other hand, are a specific place in the URL, where parameters will be injected into the code.

When should you use what?

As a general rule of thumb, you should use query params when you are dealing with optional values and route params when values are mandatory (meaning the page will not make sense without those value. This is only a rule of thumb, as you might prefer to using query params for mandatory values for easier seeing what key the value belongs to and when dealing with many mandatory values. Otherwise, route params can be hard to manage when passing eg. 10 variables to the app through the URL, because it will be very confusing to grasp what keys the values belong to and maintain the order of the values.

Implementing query param synchronization

First of all, we need to set up an Angular app with Redux. This can be done by simply cloning my Redux starter repo, which gives you a nicely structured starter template for redux apps using the Angular style guide best practices.

We handle query params using an adapter for having a nice and easy interface dealing with query params.

Now we have a service for getting query params using an easy interface. As I have written about before this is an adapter to handling query params, so the app is not directly interacting with the Angular router API but instead a simple high-level facade.

Next step is to use this in the Redux Query param sync service:

The query param sync service operates with query param sync objects which are encapsulated logic of how the query param should be synced with a specific action or method.

The property selectorToUpdateQueryParam$ is a store selection observable. When this emits the query param is updated.

The property selectorToUpdateQueryParam$ is a method/action that is fired every time the query param changes.

The query key is the actual query param key displayed in the URL.

The query param synchronization service is started with startSyncQueryParams where the synced query param objects are passed in. From here subscriptions for every query param object will be set up with the selector observable, the method to be triggered on query change and query key, ensuring proper synchronization between Redux store and query param.

You want to be able to add query param sync objects at runtime, which is what addSyncedQueryParam enables. This will stop the current query param synchronization and add the new query param sync object to the synced query params and start query param sync again. This is handy when you want to sync a query param that belongs to a feature module. This can be set up in onInit of the feature component.

Likewise, you can clean up query params using unsyncQueryParam, which will unsubscribe the given query param. This can be set up in onDestroy in a feature module.

The Redux query param sync service will start syncing when you invoke startSyncQueryParams like this:

Conclusion

We now know why to cross-cutting concerns such as caching, logging and query param handling should be implemented in a way that allows extending the codebase without actually modifying the code, called aspect-oriented programming. when its smart to use query params vs router params to pass data from the URL and how to handle query params aspect-oriented using a Redux query param sync service.

Do you want to become an Angular architect? Check out Angular Architect Accelerator.

Related Posts and Comments

The Complete Guide to NgRx Testing (2020)

The main secret behind having better test coverage in an Angular app is to reduce the friction it takes to write tests and enforce test coverage by setting a test coverage threshold to be checked on every commit. NgRx and reactive testing is an area where many people get confused because it seems hard to write

Read More »

How to design Redux apps for scalability and type-safety

Previously I have written about three ways to use Redux, but how do you structure your Redux app for a scalable application? Redux is good for state management in big applications because you get to decouple write from read and you are not dependent on passing data through (potentially) many levels of components. But structured

Read More »

Is Redux dead? 3 ways to use redux in your Angular app

Using Redux in React apps has become the industry standard for building scalable React apps, but with Angular, it is not so obvious when to use Redux because Angular already provides services, which can manage state. Through my work with clients I have come up with the three ways I see Redux is used with

Read More »

1 thought on “Creating query param synchronization with Redux”

  1. Pingback: How to Cache HTTP Requests in an Angular App (PWA) – Christian Lüdemann IT

Leave a Comment

Your email address will not be published. Required fields are marked *