web-dev-qa-db-ja.com

Reduxアプリのソートはどこで処理する必要がありますか?

アクション/レデューサー/コンポーネントがあります。コンポーネントの1つ(コンポーネントダンプ)にSelectがあります。ストアのフィルターの種類に関する情報を取得します。アクションまたはレデューサーでどこで処理できますか?

23
ZPPP

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

}
6
Spock

IMO、データを並べ替える適切な場所は、レデューサーではなくselectorsです。

Redux docsから:

派生データの計算

再選択は、メモ化された構成可能なセレクタ関数を作成するためのシンプルなライブラリです。再選択セレクターを使用して、Reduxストアから派生データを効率的に計算できます。

現在、セレクタを使用してデータをフィルタリングおよびソートしています。

  1. 状態にデータの繰り返しはありません。特定の方法でソートされたアイテムのコピーを保存する必要はありません。
  2. 同じデータを異なるコンポーネントで使用できます。各コンポーネントは、たとえば異なるソート関数を使用してソートします。
  3. アプリケーションにすでにあるセレクタを使用して、多くのデータ計算を適用するセレクタを組み合わせることができます。
  4. 正しくすれば、セレクターは純粋な関数になり、簡単にテストできます。
  5. 多くのコンポーネントで同じセレクターを使用します。

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

8
Atanas Korchev

セクション辞書パターンを使用してレデューサーをソートしました。言い換えると、日付などのヘッダーでアイテムを並べ替え、日付キーでオブジェクトを配列に格納します。

sectionHeaders: ["Monday", "Tuesday"],
dict:{
    Monday: [{obj1},{obj2},{obj3}],
    Tuesday: [{obj4}],
}

次に、このビューをReact Nativeで使用します。ListViewはcloneWithRowsAndSectionsメソッドを使用してセクションを含むアイテムをレンダリングするこのオブジェクト形式を除外するため、ListViewに入力します。

私のソートは簡単ではないため、これはパフォーマンスの最適化です。深く比較する必要があるので、この方法は、シーンをレンダリングするたびにではなく、最初にストアにデータを入力するときに一度だけ行います。

また、IDで辞書を使用し、実際のオブジェクトではなく、ソートされた辞書にIDのみを保存することで遊んでいました。

ただし、これにはトレードオフがあります。更新がより複雑で、アイテムがセクションから削除された場合にセクションヘッダーを削除するタイミングを決定する必要があるためです。

1
ssomnoremac