reactjsreduxredux-framework

Where should I handle sorting in Redux App?


I have an action / reducer / components. In one of my components (component dump) I have a Select. I get information on what type of filter my store. Where can I handle it in action, or reducer?


Solution

  • I save the items, sortKey and sortKind (asc/desc) in the Redux Store.

    In my Angular component (I believe would be same for React), I get the store state as an Observable so that I can display the items, sortKey and sortOrder in the UX.

    When the user clicks on the table columns to change sort key (order) I dispatch the new keys/sort order to reducer for the state.

    The reducer then performs the new sorting, and returns the new state with the updated values.

    The Observable in the component thus sparks an event which updates the UX.

    Advantage:

    My reducer ( "bizzes" is my items list, and I use Immutable.List to store the items)

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

    And my component ( I use Ng2-Redux to get the store as 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); 
        }
    }
    

    As you can see, I am using an Action (called BizzActions) to do the actual Redux dispatch. You could do it in your component, but I prefer to separate these things. For good measure, here's my BizzActions (a Service):

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