У меня есть действие/редуктор/компоненты. В одном из моих компонентов (компонентный дамп) у меня есть Select. Я получаю информацию о том, какой тип фильтра в моем магазине. Где я могу справиться с этим в действии или редукторе?
Где я должен обрабатывать сортировку в приложении Redux?
Ответ 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 вместо реальных объектов.
Для этого существуют компромиссы, поскольку это обновление является более сложным, и вам нужно решить, когда удалять заголовки разделов, если элемент удален из раздела.