Reputation: 1530
I have a redux application in flight that works very well. However, as a result of some db queries, one of the data structures stored in the state tree can contain 60,000+ entries. This can slow down the reaction time of the react ui considerably.
I do not have a large amount of reducers involved (maybe 20?) so I don't think redux-ignore could help. The data in the large data structure is read-only and does not need to be updated. However, with it loaded, using immutability-helper's update() or merge() on different sections of the tree can be slow.
Is this expected behavior? I am considering moving the data structure to localStorage, but storing it in the state tree keeps the code simple (as well as making broadside-loading the state easy).
Suggestions?
markerikson: No harm in sharing the reducer and the data structure! The only reducer responsible for the data structure part of the state is:
export function plotReducer(state={}, action) {
switch(action.type) {
case EMIT_PLOT_DATA_REQ:
return update(state, {$set: action.payload.data });
default:
return state;
}
}
This data structure is written into the state when received and then only "read" by the plot charts that use it. It is never modified.
The data object stored in the state, as received from the server, is an object containing multiple arrays of objects (as required by recharts and other plotting libs).
The store is created with:
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducers,
initialState,
composeEnhancers(
applyMiddleware(
ReduxPromise,
ReduxThunk
)
));
and I use combineReducers in an index file to create the rootReducer.
Having looked into Immutable.js I may just store the data object in its own structure outside the state.
EDIT: Insert clue-by-four. The state has been performing well. The chart libs draw svg and they're slow with large data sets. I was causing them to re-render too often w/o being aware of it. Based on the feedback below I spent the day profiling the app and the state machine is fine.
Upvotes: 2
Views: 1420
Reputation:
You should consider using Immutable.js for your state. We've done apps with data structures as large as yours, and the UI is still very responsive after initial load. To my understanding, this is because the internals of the Immutable data structures pass around references to existing objects when it can. So when a single entry changes, it reuses 99% of the data instead of recreating the whole object from scratch. This allows state changes and component updates to be super quick.
Basically, if your state object isn't immutable, you're creating a brand-new state object every time your state changes, which includes rewriting your 60k+ entries.
UPDATE: Mark Erikson is correct below when he says that you can get around the rewrite issue by using "shallow clone" methods and making sure your reducers are compartmentalized in an effective way. However, I've also found that this is easy to accidentally mess up and can ruin your optimizations in places you don't expect. Immutable.js helps keep you away from these pitfalls, but also has its drawbacks. Check out this article from the Redux docs to help determine if it is in fact your best option. http://redux.js.org/docs/recipes/UsingImmutableJS.html
Upvotes: 1
Reputation: 67459
How are you currently trying to update the store? Even without use of Immutable.js, standard "shallow clone" approaches such as Object.assign
and the ...
object spread operator should leave existing references and fields intact. And, if you have a reducer that handles a LOAD_THE_LARGE_DATASET
action, I would expect that the rest of the time it just returns its existing state slice unchanged.
Also, what makes you say that this part of the tree is "slowing down the reaction time of the React UI"? Do you have some specific benchmarks that relate to this? What operations are "slow"?
You may want to read through the Redux FAQ section on immutable data handling in Redux for reference.
Upvotes: 2