アクション/レデューサー/コンポーネントがあります。コンポーネントの1つ(コンポーネントダンプ)にSelectがあります。ストアのフィルターの種類に関する情報を取得します。アクションまたはレデューサーでどこで処理できますか?
ReduxストアにsortKeyとsortKind(asc/desc)というアイテムを保存します。
私のAngularコンポーネント(Reactでも同じだと思います)で、UXでアイテム、sortKey、sortOrderを表示できるように、ストアの状態をObservableとして取得します。
ユーザーが並べ替えキー(順序)を変更するためにテーブル列をクリックすると、新しいキー/並べ替え順序を状態のレデューサーにディスパッチします。
次に、リデューサーは新しい並べ替えを実行し、更新された値で新しい状態を返します。
したがって、コンポーネントのObservableは、UXを更新するイベントを引き起こします。
利点:
コンポーネントからロジックをソートし続ける
状態でsortKeyとsortKindを保存することにより、ユーザーがブラウザーを更新した場合に正確に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);
}
}
ご覧のとおり、実際のReduxディスパッチを実行するためにAction(BizzActionsと呼ばれる)を使用しています。コンポーネントでそれを行うこともできますが、これらを分離することを好みます。適切な測定のために、ここに私の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
}
});
};
}
IMO、データを並べ替える適切な場所は、レデューサーではなくselectorsです。
Redux docsから:
再選択は、メモ化された構成可能なセレクタ関数を作成するためのシンプルなライブラリです。再選択セレクターを使用して、Reduxストアから派生データを効率的に計算できます。
現在、セレクタを使用してデータをフィルタリングおよびソートしています。
ReduxストアでReactコンポーネントを@connect -ingするときにデータをソートできます。
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で使用します。ListViewはcloneWithRowsAndSections
メソッドを使用してセクションを含むアイテムをレンダリングするこのオブジェクト形式を除外するため、ListViewに入力します。
私のソートは簡単ではないため、これはパフォーマンスの最適化です。深く比較する必要があるので、この方法は、シーンをレンダリングするたびにではなく、最初にストアにデータを入力するときに一度だけ行います。
また、IDで辞書を使用し、実際のオブジェクトではなく、ソートされた辞書にIDのみを保存することで遊んでいました。
ただし、これにはトレードオフがあります。更新がより複雑で、アイテムがセクションから削除された場合にセクションヘッダーを削除するタイミングを決定する必要があるためです。