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

  1. Вам не нужно хранить отфильтрованные результаты в дереве состояний

Cons

  1. Поскольку отфильтрованные результаты не хранятся в дереве, вам нужно будет импортировать этот селектор везде, где вы хотите получить доступ к этим данным.
  2. Вы не сможете получить к нему прямой доступ, например, 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

  1. Вы сможете вручную получить доступ к вашим FilterResults, поскольку они хранятся в дереве.

Cons

  1. Вам нужно будет убедиться, что каждое действие, изменяющее что-либо реализованное, отфильтрованные результаты обновит их.
  2. Вы будете хранить дополнительные данные в магазине (результаты + отфильтрованные результаты).

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

  1. отфильтрованные результаты можно хранить в другой части дерева, где хранятся результаты или входное значение.

Cons

  1. вам нужно дополнительное действие для хранения отфильтрованных результатов.
  2. Вы отправляете 2 действия по отдельности, которые могут вызвать дополнительную визуализацию.

Окончательное рассмотрение

Вы можете выбрать наиболее подходящий и эффективный способ в зависимости от ваших потребностей.

Мне лично нравится использовать селекторы (1) и пересчитывать данные, поскольку это позволяет мне отделить логику от действий и редукторов.

Другие вопросы по тегам