Redux performance with large objects

2019-07-29 19:10发布

问题:

I am using Redux and React to build a web application. My application is an analytics application that renders a lot of data. I am running into performance issues when my store becomes large.

What is the preferred way of avoiding performance issues with large data in redux?

Application Structure

My app is structured in a way where I have settings (small json), results (large json), and calculate(settings). Calculate is deterministic and idempotent. My app renders settings metadata and the results in graphs, tables, etc.

Because calculate is deterministic and idempotent, I know results will not change when settings does not change. When settings do change my results may change. In other words, I'm comfortable relying on only settings to determine if I need to update my UI.

Redux Behavior & Potential Solutions

My application is slow when I include results inside my store:

let settings = { foo: "bar" };
let results = calculate(settings);
Object.assign({}, state, { settings: settings, results: results });

//deterministic and idempotent
function calculate(settings) {
  return /*large json*/;
}

My application is fast when I reference but don't include results inside my store:

let settings = { foo: "bar" };
let results = calculate(settings);
Object.assign({}, state, { settings: settings, results: () => results });

//deterministic and idempotent
function calculate(settings) {
  return /*large json*/;
}

I know redux advises against storing functions, so an alternative is to save a reference using a string...something like:

let settings = { foo: "bar" };
let calculationId = uuid(); //could also be a hash of settings if I want to avoid some false positive UI re-rendering
let results = calculate(settings);
setResults(calculationId, results);
Object.assign({}, state, { settings: settings, calculationId: calculationId });

//deterministic and idempotent
function calculate(settings) {
  return /*large json*/;
}

let fakeStore = { calculationId: null, results: null };

function setResults(calculationId, results) {
  fakeStore. calculationId = calculationId;
  fakeStore.results = results;
}

function getResults(calculationId) {
  if(fakeStore.calculationId === calculationId) {
    return fakeStore.results;
  }
  throw new Error("Invalid data access");
}

render() {
  let calculationId = this.props.calculationId;
  let results = getResults(calculationId);
}

Keeping large data outside of the store is tenable, but it seems like there may be better ways react supports this use case.

Using redux 3.7.1, react 15.4.2, react-redux 4.4.8

回答1:

Simply "saving values into the store" will not affect speed whatsoever. It's how you process those values in your reducers, and use them in your UI that matter. So, it's a bit hard to give specific advice, since you haven't given any info on how you're actually using that data.

In general, per the other comment, use of memoized selectors (created by the Reselect library) is helpful for only recalculating expensive derived values when the inputs actually change.

For more information on improving Redux usage performance, please see:

  • The Redux FAQ entry on scaling and performance
  • The Redux Performance section of my React/Redux links list
  • My blog post Practical Redux, Part 6: Connected Lists, Forms, and Performance


回答2:

Try Reselect. Do the result object reference change after each calculation? If that's the case, this small library should help you.