我有一个动作/减速器/组件。在我的一个组件(组件转储)中,我有一个 Select。我得到关于我的商店使用什么类型的过滤器的信息。我在哪里可以处理它,或者减速器?
4 回答
IMO,对数据进行排序的正确位置不是直接在 reducers 中,而是在selectors中。
来自 redux 文档:
Reselect 是一个简单的库,用于创建可记忆的、可组合的选择器函数。重新选择选择器可用于有效地计算来自 Redux 存储的派生数据。
我目前正在使用选择器来过滤和排序数据。
- 状态下没有数据重复。您不必存储按一种特定方式排序的项目的副本。
- 相同的数据可以在不同的组件中使用,例如,每个组件使用不同的选择器函数进行排序。
- 您可以使用应用程序中已有的选择器组合选择器来应用许多数据计算。
- 如果你做得对,你的选择器将是纯函数,那么你可以轻松地测试它们。
- 在许多组件中使用相同的选择器。
我将项目、sortKey 和 sortKind (asc/desc) 保存在 Redux Store 中。
在我的 Angular 组件中(我相信 React 也是如此),我将商店状态作为 Observable 获取,以便我可以在 UX 中显示项目、sortKey 和 sortOrder。
当用户单击表列以更改排序键(顺序)时,我将新键/排序顺序分派给状态的减速器。
然后 reducer 执行新的排序,并返回带有更新值的新状态。
因此,组件中的 Observable 会触发一个更新 UX 的事件。
优势:
保持对组件的逻辑排序
通过将 sortKey 和 sortKind 保存在 state 中,可以在用户刷新浏览器时精确还原 UX(我使用 Redux-LocalStorage 同步)
由于商店有已排序的商品,因此您只会在用户主动需要时执行排序。
当用户可能返回组件时,会记住已排序的项目。
我的减速器(“bizzes”是我的项目列表,我使用 Immutable.List 来存储项目)
import { List } from 'immutable';
import { IBizz, IBizzState } from './bizz.types';
import { BIZZES_SET, BIZZES_SORT} from 'store/constants';
const SORT_ASC = 'asc';
const SORT_DESC = 'desc';
const defaultSortKey = 'serialNo';
const defaultSortOrder = SORT_ASC;
const INITIAL_STATE: IBizzState = {
bizzes: List([]),
sortKey: defaultSortKey,
sortOrder: defaultSortOrder
};
export function bizzReducer(state: IBizzState = INITIAL_STATE, action: any): IBizzState {
switch (action.type) {
case BIZZES_SET:
return {
bizzes: List(action.payload.bizzes),
sortKey: action.payload.sortKey || defaultSortKey,
sortOrder: action.payload.sortOrder || defaultSortOrder
};
case BIZZES_SORT:
let sortKey = action.payload.sortKey || defaultSortKey;
if(sortKey === state.sortKey) {
state.sortOrder = state.sortOrder === SORT_ASC ? SORT_DESC : SORT_ASC;
}
return {
bizzes: List(state.bizzes.sort( (a, b) => {
if( a[sortKey] < b[sortKey] ) return state.sortOrder === SORT_ASC ? -1 : 1;
if( a[sortKey] > b[sortKey] ) return state.sortOrder === SORT_ASC ? 1: -1;
return 0;
})),
sortKey: sortKey,
sortOrder: state.sortOrder
};
default: return state;
}
}
还有我的组件(我使用 Ng2-Redux 将商店作为 Observables 获取):
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core';
import { select } from 'store';
import { BizzActions } from 'actions/index';
@Component({
selector: 'bizzlist',
templateUrl: './bizz-list.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class BizzListComponent implements OnInit {
@select([ 'bizzState']) bizzState$;
public sortOrder: string;
public sortKey: string;
public bizzes = [];
private bizzStateSubscription;
constructor(
public bizzActions: BizzActions
) { }
ngOnInit() {
this.bizzStateSubscription = this.bizzState$.subscribe( bizzState => {
this.bizzes = bizzState.bizzes;
this.sortKey = bizzState.sortKey;
this.sortOrder = bizzState.sortOrder;
});
}
ngOnDestroy() {
this.bizzStateSubscription.unsubscribe();
}
public sortBizzes(key) {
this.bizzActions.sortBizzes(key);
}
}
如您所见,我使用一个 Action(称为 BizzActions)来执行实际的 Redux 调度。你可以在你的组件中做到这一点,但我更喜欢将这些东西分开。为了更好地衡量,这是我的 BizzActions(一项服务):
import { Injectable } from '@angular/core';
import { NgRedux, IAppState } from 'store';
import {
BIZZES_SET,
BIZZES_SORT
} from 'store/constants';
@Injectable()
export class BizzActions {
constructor (private ngRedux: NgRedux<IAppState>) {}
public setBizzes = (bizzes: any) => {
return this.ngRedux.dispatch({
type: BIZZES_SET,
payload: {
bizzes: bizzes
}
});
};
public sortBizzes = (key:string) => {
return this.ngRedux.dispatch({
type: BIZZES_SORT,
payload: {
sortKey: key
}
});
};
}
您可以在使用 Redux 存储 @connect 时对您的 React 组件进行排序:
function mapStateToProps(state) {
var items = state.items.slice(0);
items.sort()
return {
items: items
}
}
@connect(mapStoreToProps)
class MyComponent extends React.Component {
render() {
var items = this.props.items;
}
}
Redux 文档在 Todo 示例中显示了类似的案例:https ://redux.js.org/basics/usage-with-react
我一直在使用部分字典模式对减速器进行排序。换句话说,我按标题对项目进行排序,比如日期,然后按日期键将对象存储在数组中:
sectionHeaders: ["Monday", "Tuesday"],
dict:{
Monday: [{obj1},{obj2},{obj3}],
Tuesday: [{obj4}],
}
然后我在 React Native 中使用这个 dict 来填充我的 ListView,因为 ListView 将除了这个对象格式来使用该cloneWithRowsAndSections
方法呈现带有 Sections 的项目。
这是一个性能优化,因为我的排序不是微不足道的。我必须进行深入的比较,这样我只在第一次填充商店时做一次,而不是每次渲染场景时。
我还尝试过按 ID 使用字典,并且只将 ID 存储在排序的字典中,而不是实际的对象。
不过,这需要权衡取舍,因为更新更加复杂,如果从部分中删除项目,您必须决定何时删除部分标题。