Sharing state between AngularJS and Angular through Redux

In my previous post, about building a hybrid application with AngularJS and Angular v6 (I’ll refer to it as Angular from now on), I set up the basics of having a working application. But what happens when some actions in one of the frameworks affect the state in the other? Well, then you’re in trouble because accessing the $rootScope in Angular is a bad idea and the other way around is just too complicated to spend any time on. Bring in Redux, the centralized state manager.

It’s not just used with React

Redux?! Isn’t that some React thing? No, in fact, it’s a vanilla JavaScript library to create a single JavaScript object that contains some data. This means you can use it in React, VueJS, Angular, jQuery, etc. You can even use it without a framework if you so choose. It’s simply JavaScript. I’ve worked with Redux once before, but back then, I was building two completely different frameworks to work next to each other, never touching one another. This time around, it’s two frameworks, implementing each other and talking with each other all the time. This is the perfect situation to let Redux help me out again.

Setting up Redux

The first step is to set up Redux, without thinking about any frameworks. We have to set up some actions we wish to trigger, some reducers to deal with any changes in the current state, and a store to bring it all together. This store will then be “provided” in both AngularJS and Angular. When this is completed we’ll be able to dispatch actions in both frameworks and subscribe to any changes, to be able to synchronize the states of the two different frameworks.

So first, let’s create a basic Redux set-up. This article is not a tutorial, so if you wish to learn what’s going on here, I suggest you read the official documentation. I used that as a guide to creating my own set-up, so it won’t differ much to your own implementation.

If you really wish to follow along with my steps, here’s my store:

This is the example store I’ll be using in this post

The rootReducer will be displayed later on in this blog, so don’t worry about it just yet. The INITIAL_STATE and its interface are displayed below:

The initial state for this post

In this initial state, I set my languages property to an empty array, this means that when Redux is started, it’ll have an empty value, but the value is there and ready to be filled with data. The initial state has the type IAppState, which is the following:

The ILanguage interface I won’t display because it’s not relevant to this blog. This can literally be anything you can think of. It’s just telling TypeScript that the languages property will be filled with an array of ILanguage’s. This could be a string, an integer or a boolean.

Setting up dispatchers and subscribers

As soon as you’ve set up Redux, you can start to dispatch actions and subscribe to these events. I think you’re starting to see where this is going. You’re going to use a framework-agnostic library to share data between two "separate" frameworks. Every time you dispatch an action, a subscriber will receive the data in the form of a new version of the Redux state. This means you can dispatch actions in either framework, add subscribers wherever you want, and exchange pieces of data seamlessly. You can even use it to exchange data within the same framework if you want to. In case of AngularJS, this could help you fully remove the use for the $rootScope.

Ng-Redux

To easily integrate Redux in AngularJS, I used the NPM package “ng-redux”. This is fully optional, as you don’t need it to make Redux work, but it makes the integration with AngularJS a bit simpler. You can install this by issuing the following command:

yarn add ng-redux

or in case you don’t use yarn:

npm install ng-redux -S

When you’ve included this package in your project, you have to link it with the Redux store you’ve created in the Redux guide I mentioned earlier. The GitHub page I linked above, wants you to create a new store, just for AngularJS, but this is not something we want to do. We’ve already created the store and we don’t just want to use it in AngularJS. So use the following code to initialize ng-redux with an existing store:

A simple way to initialize Redux in your AngularJS app

What I’m doing here is simply including the libraries I need: Angular, ng-redux, and the Redux store I’ve created earlier. Then I’m telling ng-redux to use an existing store, instead of creating a new one. We need to use this existing store because that allows us to communicate between AngularJS and Angular. Now let’s get to Angular.

@angular-redux/store

I did a similar thing in Angular but using the appropriate package this version. This package is called: “@angular-redux/store”. Again, use either of the commands below:

yarn add @angular-redux/store

or in case you don’t use yarn:

npm install @angular-redux/store -S

In AngularJS I showed you that I provided the existing Redux store to ng-redux. This is exactly what we’re going to do for Angular as well:

Initialize @angular-redux/store in the AppModule in Angular

Note that this is a stripped down version of my actual AppModule, so don’t simply copy and paste this into you’re own project. What I’m doing in this snippet is including the NgReduxModule and the Injector from the @angular-redux/store package, alongside the exact same store as I’ve included in the AngularJS snippet, and an interface that TypeScript loves so much. In the constructor of the AppModule, I’m providing NgRedux with the store I’ve created earlier and have already provided in AngularJS. We’re ready to let the frameworks interact with each other!

Preparation time

To keep this part simple, I’m going to show you two things: AngularJS dispatching an event and Angular receiving it. The communication in the other ways is very easy when you know how to do it from one to the other.

First I’ll show a small snippet of an action with a reducer, so you sort of know what’s going on in this particular case.

This is an example action you could dispatch in this Redux store

For demonstration purposes, I’ve only included a single action that you can dispatch in the Redux set-up. I use constants to determine the actions because they can be type-hinted in PhpStorm and it saves me time.

This is an example of a RootReducer with a single reducer

This is a root reducer with a single provided reducer, the languages reducer. If you have just one reducer, it is not necessary to use a combineReducers. But this is a simplified snippet of the real set-up, so I have about 15 reducers in there.

This is the example language reducer that’s being provided in the RootReducer

This is the actual languages reducer I use. As you can see, the default value I give here is part of the INITIAL_STATE constant. This makes sure I get a predictable value back in case I choose to ignore a state change. All this reducer does is return an array filled with objects of type ILanguage. As I’ve noted before, it’s not important what this type actually is. You could just read it as an array of strings.

Time to start talking

So with the store, the actions, and the reducers in place, we can start to dispatch actions and receive data. First of all, let’s look at what it would be like for AngularJS to dispatch an action with some data and Angular to receive this data:

AngularJS dispatching a new language with Redux

AngularJS just dispatched an action. It contains a simple JavaScript object containing some data. Let’s see how to catch this data in Angular.

Angular receiving the data in a random component

Here you can see how Angular is receiving the data in a component. Now you’ve got the same data in two different frameworks. This can help you keep them both in sync and work together seamlessly. Sharing data doesn’t have to be difficult. With this same principle, you can dispatch an action in Angular and receive the data in AngularJS. But I’m going to let you figure out how to do that yourself :) (it’s in the documentation of both ng-redux and @angular-redux/store, don’t worry!).

Conclusion

Sharing data between frameworks doesn’t have to be difficult, once you know how it works. I demonstrated how you can send data between AngularJS and Angular in this post, but you could easily change this to Angular/React, React/VueJS/Angular, AngularJS/VueJS, and hey, let’s have some fun, React/jQuery. It doesn’t matter which framework you use, as long as you’re using JavaScript (or TypeScript in my case), you can already use Redux in your project.

If you have any suggestions on how I can improve my content or my examples, please let me know! I’m always open for suggestions. If you have any questions, you can ask them in the comments and I’ll answer them to the best of my abilities.