Is it possible to implement a Redux-like architecture in Angular 1 using $ rootScope as a store?

If you are in a large Angular 1 database and you do not want to introduce new dependencies (for example, ngRedux), it would be a terrible idea to start using the classic Angular 1 functions such as $ rootScope, $ broadcast, $ on, $ watch to implement a similar Redux architecture?

As I see it, this can be done as follows:

  • For store / model โ†’ use $rootScope
  • For store.dispatch(ACTION) use $rootScope.$broadcast(ACTION)
  • The $rootScope will be implemented as services injecting $rootScope and performing $on(ACTION)
  • Controllers could monitor changes to $rootScope using $watch and update the view or views could directly bind to the properties of $rootScope

As long as you are disciplined not to make strange mutations out of place on the properties of $rootScope , keep all the application logic in the gearboxes and keep the controller code to a minimum, the biggest drawback I see with this: having terrible performance due to Angular 1 expensive digest cycles. But if you can also stick with immutable data structures , this may not even be so.

It is a bad idea? Has anyone tried this?

+5
source share
1 answer

Of course, you can do your thing using only $rootScope . But there are many other goals that will interfere with your state.

We will see:

 // reducer-like $rootScope.$on('COUNTER_INCREMENT', (e, action) => { //I don't use += to emphase immutability of count property; $rootScope.count = $rootScope.count + action.value; }); //action-ish creator $rootScope.$broadcast('COUNTER_INCREMENT', {value: 5}); //store subscribe-like $rootScope.$watch('count', (count) => { //update something in your component }) 

You can do this if you want, but you see there a problem with unclear immutability. It is very difficult to control that your action handler is clean, because in reality it is not.

There is no default action handler; you cannot easily set the initial state of the repository. And you still use $watch and digests, which you probably want to avoid.

In addition, you cannot subscribe to all updates, there is no single reset point of everything, as Redux does with time travel.

If you want to use Redux as a template, you will probably end up with some helpers that will make your code more like Redux.

Well, why not just start using Redux from a simple angular utility:

 angular.module('app', []).factory('store', () => { //if you have many reducers, they should be as separate modules, and imported here function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + action.value; default: return state; } } // here you can add here middlewares that make Redux so powerful return Redux.createStore(counter); }); 

Here we go. Now you can use the service of your store for action.

 angular.module('app').controller('MyController', ($scope, store) => { store.subscribe(() => { //you may not to care about $scope.$digest, if your action was triggered within angular scope as well $scope.count = store.getState(); }); $scope.onClick = () => store.dispatch({type: 'INCREMENT', value: 1}); }); 

Now you have the correct setting, in which your subscribers are not aware of the action that caused the dispatch, your action and the logic of actions are completely independent, as required by the Redux template.

+7
source

Source: https://habr.com/ru/post/1246876/


All Articles