Redux реагирует на замедление корневого редуктора
Я создаю приложение с использованием реакции и редукса. Одной из функциональных возможностей является фильтрация результатов по состоянию. Таким образом, в каждом компоненте класса у меня было что-то вроде этого:
filteredResults = this.filterResults(this.props.value1, this.props.value2,...)
Теперь я подумал, что должен быть выигрыш в производительности, если я просто добавлю фильтрованные результаты в состояние избыточности и введу RootReducer. На самом деле, это замедлило работу приложения. Любая идея, почему это произошло? Для меня это немного нелогично, так как FilterResults вычисляется прямо сейчас много раз.
PS: Вот так выглядел мой RootReducer:
import {_getFilteredResults} from "../components/utils";
const createFilterRootReducer = reducer => (state, action) => {
let reduced_state = reducer(state, action);
let filteredResults = _getFilteredResults(reduced_state.value1, reduced_state.value2, reduced_state.value3, reduced_state.results);
return {...reduced_state, filteredResults:filteredResults}
};
export default createFilterRootReducer;
Это было применено на my RootReducer
const rootReducer = combineReducers({
searching: ReducerSearching,
roomOption: ReducerZimmer,
maxPrice: ReducerMaxPrice,
minPrice: ReducerMinPrice,
internalMaxPrice: ReducerInternalMaxPrice,
Address: ReducerAddress,
Results: ReducerResults,
activePage: ReducerActivePage,
favoriteResults:ReducerLikedItems,
resultSort: ReducerSort,
acceptedCookie: ReducerCookies,
headerHeight: ReducerHeaderHeight,
mapView: ReducerMapView,
rehydrate: ReducerRehydrate
});
export default createFilterRootReducer(rootReducer);
Еще одна вещь: я также использовал "redux-persist" для сохранения состояния!
1 ответ
Что ж, было бы полезно, если бы вы могли предоставить дополнительную информацию и код, который вы используете.
Я считаю, что есть как минимум 3 способа сделать то, что вы хотите достичь.
1. Используйте createSelector от повторного выбора
На мой взгляд, самый простой способ - использовать селектор для расчета отфильтрованных результатов на основе фактического состояния всех результатов и значений фильтрации.
import { createSelector } from 'reselect';
const getResults = state => state.results; // e.g. array of strings
const getFilter = state => state.filter; // e.g. an input value
export const filteredResults = createSelector( getResults, getFilter, ( results, filter ) => {
return results.filter( item => item.indexOf( filter ) != -1 );
});
Теперь вы можете предоставить filteredResults
через connect и mapStateToProps для ваших компонентов, не беспокоясь о фильтрации ваших результатов каждый раз.
Обратите внимание, что createSelector
достаточно умен, чтобы выполнить проверку на равенство своих параметров, чтобы пересчитать функцию только при изменении любого из ее параметров.
Pros
- Вам не нужно хранить отфильтрованные результаты в дереве состояний
Cons
- Поскольку отфильтрованные результаты не хранятся в дереве, вам нужно будет импортировать этот селектор везде, где вы хотите получить доступ к этим данным.
- Вы не сможете получить к нему прямой доступ, например,
state.xyz.filteredResults
2. Сохраните отфильтрованные результаты в дереве при сохранении всего, что может их изменить.
Вы можете рассчитать и сохранить фильтрованные результаты в той же ветви дерева, где (и когда) вы сохраняете результаты и входное значение. Это возможно только в том случае, если ваши исходные результаты хранятся в одном месте.
const initialState = {
results: [],
filteredResults: [],
filter: ''
}
const filterResults = ( results, filter ) => results.filter( item => item.indexOf( filter ) )
const myReducer = handleActions({
[SET_RESULTS]: (state, action) => ({
...state,
results: action.payload,
filteredResults: filterResults( action.payload, state.filter )
}),
[SET_FILTER]: (state, action) => ({
...state,
filter: action.payload,
filteredResults: filterResults( state.results, action.payload )
})
}, initialState)
Pros
- Вы сможете вручную получить доступ к вашим FilterResults, поскольку они хранятся в дереве.
Cons
- Вам нужно будет убедиться, что каждое действие, изменяющее что-либо реализованное, отфильтрованные результаты обновит их.
- Вы будете хранить дополнительные данные в магазине (результаты + отфильтрованные результаты).
3. Используйте Redux-Thunk и сохраните отфильтрованные результаты
Это другой подход, который будет работать. В основном вы можете сохранять отфильтрованные результаты в другой части дерева при вводе, но для этого вам понадобится промежуточное ПО Redux Thunk
export const onChangeInputValue = ( value ) => {
return (dispatch, getState) => {
const results = getResults( getState() )
const filteredResults = results.filter( item => item.indexOf( value ) )
dispatch( setInputValue( value ) )
dispatch( setFilteredResults( filteredResults ) )
}
}
Pros
- отфильтрованные результаты можно хранить в другой части дерева, где хранятся результаты или входное значение.
Cons
- вам нужно дополнительное действие для хранения отфильтрованных результатов.
- Вы отправляете 2 действия по отдельности, которые могут вызвать дополнительную визуализацию.
Окончательное рассмотрение
Вы можете выбрать наиболее подходящий и эффективный способ в зависимости от ваших потребностей.
Мне лично нравится использовать селекторы (1) и пересчитывать данные, поскольку это позволяет мне отделить логику от действий и редукторов.