1

I am receiving new data points in real time, and I am trying to use the react useState hook to update my data. There may be several hundred thousand points, so updates need to be efficient. The structure of my state looks roughly like this:

{
  "graph1": {
    "line1": [[x1, y1], [x2, y2],..., [x100, y100]],
    "line2": [[x1, y1], [x2, y2],..., [x200, y200]],
    "line3": [[x1, y1], [x2, y2],..., [x900, y900]]
  },
  "graph2": {
    "line1": [[x1, y1], [x2, y2],..., [x100, y100]],
    "line2": [[x1, y1], [x2, y2],..., [x200, y200]]
  }
}

Where the xi, yi are just floating point numbers. I receive updates in a similar format, for example:

{
  "graph1": {
    "line1": [[x101, y101]],
    "line3": [[x901, y901], [x902, y902]],
    "line4": [[x1, y1]],
  },
  "graph2": {
    "line1": [[x101, y101]],
  }
}

And I would like to update my state so that it looks like this:

{
  "graph1": {
    "line1": [[x1, y1], [x2, y2],..., [x101, y101]],
    "line2": [[x1, y1], [x2, y2],..., [x200, y200]],
    "line3": [[x1, y1], [x2, y2],..., [x902, y902]],
    "line4": [[x1, y1]]
  },
  "graph2": {
    "line1": [[x1, y1], [x2, y2],..., [x101, y101]],
    "line2": [[x1, y1], [x2, y2],...,  [x200, y200]]
  }
}

Is there an easier way to do this than with a mess of spread operators? i.e.

setGraphs(xs => ({
  ...xs,
  "graph1": {
    ...xs.graph1,
    "line1": [...xs.graph1.line1, ...new_data.graph1.line1],
    // etc
})

In particular, with the spread operator approach, it's not clear to me how to handle a dynamic set of keys - for example, the new "line4" key in the update above.

I have full control over both the structure of the data and the structure of my react code, so if there is a more idiomatic way to achieve the same goal I would love to hear that too.

2 Answers 2

2

You could regenerate the state and reset it. Your solution only works when you know all the possible keys but otherwise, we need to merge them by iteration. Like this:

setGraph(graph => {
  Object.keys(newData).forEach(g => {
    Object.keys(newData[g]).forEach(l => {
      if (graph[g][l]) {
        graph[g][l] = [...graph[g][l], ...newData[g][l]);
      } else {
        graph[g][l] = newData[g][l];
      }
    });
  });
  return graph;
});
Sign up to request clarification or add additional context in comments.

6 Comments

How efficient is this? If my existing state is large, but newData is small, will this run quickly?
I doubt that the update data will be large. This is O(n*m), but still if the update data is not big, it will be fast.
What are n,m here? For my application, typically, the existing state graph will have 10000-100000 points, and the update data newData will have 10-100 points.
n: number of graphs, m: number of lines. we can't go faster than O(n*m) here. if it's 10-100 points, it will be very fast though.
In the new data.
|
0

Spread operator is the best way to update objects or arrays. One of the new features in ECMA Script 2015 and above.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.