Apollo GraphQl Storing derived data

2020-05-01 04:49发布

问题:

Some context: I'm developing a React JS app that reads geographic points out of a database and graphs/maps them in various ways. There are raw maps and plots that just show data straight from the database but there are also plots and metrics that involve analysis on the points like slope plot, area under graph, histograms, Euclidean distance etc.

I have a GraphQL client set up to feed me data to my react app with Apollo-Client installed. Here's a sample of the GraphQL response:

{
  "data": {
    "Points": [
      {
        "pid": 13196,
        "x": 251.88491821289062,
        "y": 374.1650085449219
      },
      {
        "pid": 13197,
        "x": 257.6238708496094,
        "y": 374.17498779296875
      },
      {
        "pid": 13198,
        "x": 264.04315185546875,
        "y": 374.5350036621094
      },
      ...etc
    ]
  }
}

This is great! This is the right shape for at least 2 different views on the data, Apollo client caches this for me using InMemoryCache and I haven't needed redux at all yet.

Dilemma: A bunch of the plots I need involve a lot of derived values that get reused (like I might use the slope values in 2 different views). Where should I store my derived data?

Right now I have all the calculations crammed into React render() methods but that's doesn't seem like a good idea.

Options:

  1. Use Redux for the derived data, put all the calculations into reducers and somehow keep it synched up with what's in the Apollo graphql cache.
  2. Do the derivation on the server (which I can then cache) and send both raw + derived over the network. More network traffic but less client computation.
  3. Continue calculating the derived values inside render() whenever the incoming graphql data changes.
  4. Maybe something I haven't thought of...

回答1:

  1. Redux can be quite good option - separation of concerns/logics/data and good testability.
  2. It depends of eventual cache hit/miss ratio, costs of additional resources/power - I would avoid that.
  3. Render is not optimal place (there're other lifecycle methods) for calculations. Component can use own state (or new getDerivedStateFromProps) but shared with children only.
  4. You can use react context api or apollo-link-state to share data/methods. You can try observables/mobx-like solutions.

I would also avoid automatic all possible recalculations on data updates. With components/lifecycles/contexts you can prepare (cache and share) derived data when it really will be used.