Redux 反应根减速器变慢
Redux react root reducer slowing down
我正在使用 React 和 Redux 构建应用程序。一个功能特性是根据状态过滤结果。
所以在每个 class 组件中我都有这样的东西:
filteredResults = this.filterResults(this.props.value1, this.props.value2,...)
现在我认为,如果我只是将 filteredResults 添加到 redux 状态并引入 RootReducer,应该会提高性能。实际上,这减慢了应用程序的速度。知道为什么会这样吗?对我来说,这有点违反直觉,因为 filteredResults 现在被计算了很多次。
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;
已应用于 myRootReducer
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' 来保持状态!
嗯,如果你能提供一些额外的信息和你正在使用的代码,那将会很有帮助。
我相信至少有 3 种方法可以实现您想要的目标。
1。使用 createSelector from reselect
我认为最简单的方法是使用选择器根据整个结果的实际状态和过滤值计算过滤结果。
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 );
});
现在您可以通过 connect 和 mapStateToProps 向您的组件提供 filteredResults
,而不必担心每次都会过滤结果。
请注意,createSelector
足够聪明,可以对其参数执行相等性检查,以便仅在 其任何参数发生变化时重新计算函数 。
优点
- 您不需要将过滤后的结果存储在状态树中
缺点
- 由于过滤后的结果未存储在树中,因此您需要在要访问此数据的任何地方导入此选择器。
- 您将无法通过直接方式访问它,例如
state.xyz.filteredResults
2。当存储任何会改变它们的东西时,将过滤后的结果存储在树中。
您可以计算 filteredResults 并将其存储在存储结果和输入值的同一树枝中(以及何时)。
仅当您的原始结果存储在同一位置时才有可能。
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)
优点
- 您将能够手动访问您的 filteredResults,因为它们存储在树中。
缺点
- 您将需要确保每个操作更改任何真实的过滤结果都会更新它们。
- 您将在商店中存储额外数据(结果 + 筛选结果)。
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 ) )
}
}
优点
- 您可以将过滤后的结果存储在与存储结果或输入值的树的不同部分。
缺点
- 您需要执行额外的操作来存储过滤后的结果。
- 您正在分别调度 2 个动作,这可能会导致额外的渲染。
最终考虑
您可以根据自己的需要选择最合适可行的方式。
我个人喜欢使用选择器 (1) 并重新计算数据,因为这允许我将逻辑与操作和缩减器分开。
我正在使用 React 和 Redux 构建应用程序。一个功能特性是根据状态过滤结果。 所以在每个 class 组件中我都有这样的东西:
filteredResults = this.filterResults(this.props.value1, this.props.value2,...)
现在我认为,如果我只是将 filteredResults 添加到 redux 状态并引入 RootReducer,应该会提高性能。实际上,这减慢了应用程序的速度。知道为什么会这样吗?对我来说,这有点违反直觉,因为 filteredResults 现在被计算了很多次。
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;
已应用于 myRootReducer
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' 来保持状态!
嗯,如果你能提供一些额外的信息和你正在使用的代码,那将会很有帮助。
我相信至少有 3 种方法可以实现您想要的目标。
1。使用 createSelector from reselect
我认为最简单的方法是使用选择器根据整个结果的实际状态和过滤值计算过滤结果。
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 );
});
现在您可以通过 connect 和 mapStateToProps 向您的组件提供 filteredResults
,而不必担心每次都会过滤结果。
请注意,createSelector
足够聪明,可以对其参数执行相等性检查,以便仅在 其任何参数发生变化时重新计算函数 。
优点
- 您不需要将过滤后的结果存储在状态树中
缺点
- 由于过滤后的结果未存储在树中,因此您需要在要访问此数据的任何地方导入此选择器。
- 您将无法通过直接方式访问它,例如
state.xyz.filteredResults
2。当存储任何会改变它们的东西时,将过滤后的结果存储在树中。
您可以计算 filteredResults 并将其存储在存储结果和输入值的同一树枝中(以及何时)。 仅当您的原始结果存储在同一位置时才有可能。
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)
优点
- 您将能够手动访问您的 filteredResults,因为它们存储在树中。
缺点
- 您将需要确保每个操作更改任何真实的过滤结果都会更新它们。
- 您将在商店中存储额外数据(结果 + 筛选结果)。
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 ) )
}
}
优点
- 您可以将过滤后的结果存储在与存储结果或输入值的树的不同部分。
缺点
- 您需要执行额外的操作来存储过滤后的结果。
- 您正在分别调度 2 个动作,这可能会导致额外的渲染。
最终考虑
您可以根据自己的需要选择最合适可行的方式。
我个人喜欢使用选择器 (1) 并重新计算数据,因为这允许我将逻辑与操作和缩减器分开。