angular - Redux 初始状态在 Angular 中充满空值

标签 angular redux rxjs redux-observable

我已经在一个项目上工作了大约 10 个月,该项目基于 Angular 4+ 和 Redux(通过 angular-redux/store )。该项目基本上是成功的,自一月份以来就投入生产,没有遇到任何严重问题。

但是...我对 Redux 的一个问题逐渐感到失望,我认为这个问题至少很烦人,但可能不利于维护: null初始状态值,所以,我想找出我做错了什么 - 或者这是否是 Redux 设计本身的问题。

如何重现它

这是一个简单且很好的示例:https://github.com/marinho/example-app

你只需克隆,npm install它,然后运行 ​​npm run ng serve并在浏览器上加载localhost:4200。然后转到控制台并过滤“111”以查看两行:

11111 undefined
11112 null

这是由两个可观察订阅打印的,它们分别监视 myUndefined 上的值和myObjects.country 。第一个是无效 key (未在全局状态下初始化),第二个是用 null 初始化的。 .

这些订阅的更精确位置在这里:https://github.com/marinho/example-app/blob/master/src/app/component.ts#L15

为什么会发生

众所周知,在 Redux 上,必须 configureStore具有初始状态。这样的初始状态是一棵大树,其中包含由其 reducer 初始化的所有可能的键。到初始化时,没有运行任何操作,两个 reducer 都没有任何要解析的有效负载,因此它们默认为 null在大多数情况下。

到目前为止,标准 Redux/Angular,据我所知。

现在,我的两个订阅( myUndefined$myObjects$ )观察 AnonymousSubject实例,这是 angular-redux/store 提供的 channel ,用于发出在关键路径上更新的新值(即 @select(['myObjects', 'city']) 表示 <AppState>.myObjects.city )。

问题是,随着初始状态的初始化,所有已知状态键上都有新值,但几乎所有这些值都被分配了 null .

解决方案还是黑客?

一旦有订阅监听这些 key 中的任何一个,例如 null将作为第一个值发出,这使我需要空检查,例如 .filter(x => x !== null)或类似的地方太多了。实在是太丑了。

另一种选择是使用 Epics (来自 redux-observables ),但它们必须设计良好,结果闻起来既脆弱又不那么 -可靠的堆栈。

我的印象是,这不仅仅是 angular-redux/store 本身的问题,而且实际上是全局状态的副作用。

一个简单的解决方案可能是将 angular-redux/store 修复为仅在 key 不是 undefined 时才开始发出值。再说了,避免使用 null 初始化 key 并且只是不想初始化它们。但同样,如果这是 Redux 的问题,我不确定这是否是正确的方法。

那么,有没有人遇到同样的情况或者有一个优雅的解决方案?

最佳答案

在我看来,这是 Redux 固有的。从概念上讲,Redux 是一种架构,它鼓励您将 UI 视为任何给定时间整个状态的纯粹计算。您的整个应用程序是一台大型状态机。因此,如果您将初始值设置为 null,则该选择的第一个值将为 null。如果您根本没有为字段设置初始值,则相应选择的第一个值将为未定义

这样,Redux 就会在您的应用中“拉平时间”并将其分解出来。只有当前状态和下一步操作。这一基本假设使得调试工具如此强大。

我们可以让我们的 Observables '等到第一个非零值'直到触发,但这正是我个人使用 Redux 来避免的那种时间依赖性。我的感觉是,考虑到其他人可能没有预料到,在 Angular-Redux/store 库中进行此更改可能不是正确的选择。我也不确定它会对时间旅行和其他调试工具产生什么影响。

那么,就您的情况而言,有哪些更简洁的方法来处理这些情况?

通常我会考虑以下其中一项:

1)确保您的 reducer 始终具有初始状态。

这适用于您实际上拥有合理的 key 预值的情况。因此,对于任何 reducer 控制state.myUndefined,你都可以这样做

const INITIAL_VALUE = 'some-reasonable-value';
const myUndefinedReducer = (state = 'some-reasonable-value', action) => {
    // etc.
};

通过这种方式,您可以在 reducer 本身中对默认值进行编码。

2)选择时处理

这适用于不直接与存储属性相关的选择(例如,它们是某些 RxJS 计算的结果)。它也适用于 key 的初始值是动态的情况,例如一个未定义的值,直到 API 调用填充它或类似的值。

正如您所指出的,这本质上可以归结为在多个地方进行过滤,这可能很冗长。但是在您的示例中,您可以使用 select$ 更干净地实现它。和一个Transformer :

一些实用程序文件:

export const skipNil = (obs$: Observable<any>): Observable<any> =>
    obs$.filter(v => v !== null && v !== undefined);

组件.ts:

@select$('myUndefined', skipNil) myUndefined$: Observable<any>;
@select$(['myObjects', 'country'], skipNil) country$: Observable<any>;

关于angular - Redux 初始状态在 Angular 中充满空值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44714653/

相关文章:

html - Shadow DOM 让我们实现了什么?

reactjs - 引用错误: undefinedcreateProvider is not defined

rxjs - RxJS 中的 throttleTime 与 debounceTime 之间有什么区别以及何时选择哪个?

javascript - RxJS 错误处理

javascript - 仅当另一个可观察对象在过去两秒内未发出时才从可观察对象发出

angular - 如何使用 angulafire2 正确初始化和分配可观察值?

angular - Angular 2 嵌套自定义组件中没有 FormGroupDirective 的提供者

angular - 如何设置不同路由的组件属性?

javascript - React 和 Redux Reducer 没有改变

reactjs - 将 "Row Number"添加到 react-admin Datagrid 中的列表组件