是否可以使用 $rootScope 作为存储在 Angular 1 中实现类似 Redux 的架构?

Posted

技术标签:

【中文标题】是否可以使用 $rootScope 作为存储在 Angular 1 中实现类似 Redux 的架构?【英文标题】:Is it possible to implement a Redux-like architecture in Angular 1 using $rootScope as the store? 【发布时间】:2016-08-01 17:15:23 【问题描述】:

如果你在一个大型的遗留 Angular 1 代码库中并且你不想引入新的依赖项(如 ngRedux),那么开始使用经典的 Angular 1 特性(如 $rootScope、$broadcast)是不是一个糟糕的主意, $on, $watch 来实现类似 Redux 的架构?

在我看来,它可以做到以下几点:

对于商店/模型 -> 使用 $rootScope 对于store.dispatch(ACTION) -> 使用$rootScope.$broadcast(ACTION) Reducer 将被实现为注入$rootScope 并执行$on(ACTION) 的服务 控制器可以使用$watch 监视$rootScope 上的更改并更新视图或视图可以直接绑定到$rootScope 属性

只要您遵守纪律,不要对 $rootScope 属性进行奇怪的异地突变,将所有应用程序逻辑保留在 Reducers 中并将控制器代码保持在最低限度,我能看到的最大缺点是由于 Angular 1 昂贵的摘要周期,性能很差。但是,如果您也可以坚持不可变数据结构,那可能就不是这样了。

这是个坏主意吗?有人试过吗?

【问题讨论】:

【参考方案1】:

当然,您可以只使用$rootScope 来做您的事情。但是它还有很多其他的目的会干扰你的状态。

让我们看看:

// 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
)

您可以根据需要执行此操作,但您会发现存在不可变性不明确的问题。很难控制你的动作处理程序是纯的,因为它实际上不是。

没有默认的操作处理程序,您无法轻松设置存储的初始状态。而且您仍然使用$watch 和摘要,您可能希望避免使用。

此外,您不能订阅所有更新,没有像 Redux 那样对时间旅行所做的一切重置点。

如果你想继续使用 Redux 作为一种模式,你可能会以一些帮助程序结束,这将使你的代码更像 Redux。

好吧,为什么不从一个简单的 Angular 实用程序服务开始使用 Redux:

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);
);

我们开始吧。现在您可以使用商店服务进行操作了

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);
);

现在您有了一个正确的设置,您的订阅者不知道导致调度的操作,您的操作创建和操作减少逻辑完全独立,正如 Redux 模式所要求的那样。

【讨论】:

以上是关于是否可以使用 $rootScope 作为存储在 Angular 1 中实现类似 Redux 的架构?的主要内容,如果未能解决你的问题,请参考以下文章

angular中$rootscop怎样传值

$rootScope.currentUser 在刷新时为空

$rootscope说明

在anjular中 function中的$scope和$rootscope有啥区别

[angularjs] angularjs系列笔记控制器

Angular之作用域