Где я должен обрабатывать сортировку в приложении Redux?

У меня есть действие/редуктор/компоненты. В одном из моих компонентов (компонентный дамп) у меня есть Select. Я получаю информацию о том, какой тип фильтра в моем магазине. Где я могу справиться с этим в действии или редукторе?

Ответы

Ответ 1

Я сохраняю элементы, sortKey и sortKind (asc/desc) в хранилище Redux.

В моем компоненте Angular (я считаю, что это будет одинаково для React), я получаю состояние хранилища как Наблюдаемое, чтобы я мог отображать элементы, sortKey и sortOrder в UX.

Когда пользователь нажимает на столбцы таблицы, чтобы изменить ключ сортировки (заказ), я отправляю новые ключи/порядок сортировки в редуктор для состояния.

Затем редуктор выполняет новую сортировку и возвращает новое состояние с обновленными значениями.

Наблюдаемое в компоненте, таким образом, вызывает событие, которое обновляет 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); 
    }
}

Как вы можете видеть, я использую 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
            }
        });
    };

}

Ответ 2

Вы можете сортировать данные, когда @connect -свяжите свой компонент React с хранилищем Redux:

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: http://rackt.org/redux/docs/basics/UsageWithReact.html

Ответ 3

IMO, правильное место для сортировки данных не находится непосредственно в редукторах, а в селекторах .

Из документов redux:

Вычисление производных данных

Reselect - простая библиотека для создания memoized, составных функций селектора. Селектора повторного выбора можно использовать для эффективного вычисления полученных данных из хранилища Redux.

В настоящее время я использую селекторы для фильтрации и сортировки данных.

  • Нет повторения данных в состоянии. Вам не нужно сохранять копию элемента, отсортированного по определенному пути.
  • Те же данные могут использоваться в разных компонентах, каждый из которых использует другую функцию выбора для сортировки, например.
  • Вы можете комбинировать селектор, применяя множество вычислений данных, используя селектор, который у вас уже есть в приложении.
  • Если вы поступите правильно, ваши селекторы будут чистыми функциями, тогда вы можете легко протестировать их.
  • Используйте один и тот же селектор во многих компонентах.

Ответ 4

Я сортировал свои редукторы с помощью шаблона словаря раздела. Другими словами, я сортирую свои объекты по заголовкам, говорю дату, а затем сохраняю объекты в массивах с помощью ключа даты:

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

Затем я использую этот dict в React Native для заполнения моего ListView, потому что ListView будет за исключением этого формата объекта для рендеринга Items with Sections с помощью метода cloneWithRowsAndSections.

Это оптимизация производительности, потому что моя сортировка не является тривиальной. Я должен делать глубокие сравнения, и таким образом я делаю это только один раз, когда я сначала заполняю магазин, и не каждый раз, когда я делаю сцену.

Я также играл с использованием словаря по идентификатору и сохранял только идентификаторы в отсортированном dict вместо реальных объектов.

Для этого существуют компромиссы, поскольку это обновление является более сложным, и вам нужно решить, когда удалять заголовки разделов, если элемент удален из раздела.