简体   繁体   English

Redux状态树是否应表示UI中数据的组织方式?

[英]Should a Redux state tree represent how data is organized in the UI?

The situation 情况

I have a React/Redux app that displays markers on a map, and groups them into clusters based on their proximity given the current zoom level ( similar to this example - my app differs from this example slightly in that the clusters on the map will display specific data from their child markers, and not simply a total number of child markers). 我有一个React / Redux应用程序在地图上显示标记,并根据当前缩放级别的近距离将它们分组到群集中( 类似于此示例 - 我的应用程序与此示例略有不同,因为地图上的群集将显示来自其子标记的特定数据,而不仅仅是儿童标记的总数)。

I anticipate having new markers added frequently, and the app will update to show the new markers in real-time. 我预计会经常添加新标记,应用程序会更新以实时显示新标记。

The React component structure looks something like this: React组件结构如下所示:

<Map>
  <Cluster markerIds=[...] />
  ...
</Map>

So the map re-renders the appropriate clusters every time a) new markers are added to the map, and b) the map's zoom level changes. 因此,每次a)将新标记添加到地图时,地图会重新渲染相应的聚类,以及b)地图的缩放级别更改。

I'm trying to determine the best way to organize this data in a Redux state tree. 我正在尝试确定在Redux状态树中组织此数据的最佳方法。

Option 1: Simple approach 选项1:简单方法

One option would be to keep the state tree very simple, and let the UI handle all of the clustering logic as needed: 一种选择是保持状态树非常简单,并让UI根据需要处理所有集群逻辑:

{
  markers: {
    1: { name: 'Bob', location: [-40.08, 37.62] },
    2: { name: 'Steve', location: [51.08, -25.62] },
    ...
  }
}

If I organize state in this way, the UI will have to go through every marker and recalculate the visible clusters every time the zoom level changes. 如果我以这种方式组织状态,则UI必须遍历每个标记并在每次缩放级别更改时重新计算可见群集。 With a high number of markers, that could turn out to be a lot of recalculations, and I anticipate that users will be doing a lot of zooming in and out while using this app. 有了大量的标记,这可能会导致大量的重新计算,我预计用户在使用此应用程序时会进行大量的放大和缩小。

Option 2: Store cluster groups for each zoom level 选项2:为每个缩放级别存储群集组

Another option would be to keep the cluster organization in the state tree for each zoom level (eg 1 through 19): 另一种选择是将群集组织保持在每个缩放级别的状态树中(例如1到19):

{
  markers: {
    1: { name: 'Bob', location: [-40.08, 37.62] },
    2: { name: 'Steve', location: [51.08, -25.62] },
    ...
  },
  clustersByZoomLevel: {
    1: {
      clusters: [
        {
          clusterLocation: [22.59, -21.54],
          markers: [2, 11, 4]
        },
        ...
      ]
    },
    ...2-19: {...}
  }
}

In this case, the cluster calculations would only happen when new markers are added to the map, and would only be run on the new markers, not on the entire set. 在这种情况下,只有在将新标记添加到地图时才会进行群集计算,并且只会在新标记上运行,而不是在整个集合上运行。 Zooming in or out would not require recalculating, as the cluster organization would already be stored in the state. 放大或缩小不需要重新计算,因为群集组织已经存储在该州。

The question 这个问题

So, which option makes more sense? 那么,哪个选项更有意义呢?

On the one hand, I am compelled to keep it simple and avoid premature optimization (ie go with Option 1). 一方面,我被迫保持简单并避免过早优化(即选择方案1)。

On the other hand, I can see that Option 1 could easily result in tons of recalculations happening very frequently. 另一方面,我可以看到选项1很容易导致大量的重新计算频繁发生。 And Option 2 provides a state tree that translates more directly into my React component structure. 选项2提供了一个状态树,可以更直接地转换为我的React组件结构。

Which option would you suggest, and why? 你会建议哪个选项,为什么? Are their other approaches I'm not considering that may work better? 他们不考虑的其他方法可能会更好吗?

From what you're asking, both are viable. 根据你的要求,两者都是可行的。

Due to the nature of your exact question (depending upon the scale), I would say that a caching layer is totally viable (so long as the pure data-set remains there). 由于您的确切问题的性质(取决于规模),我会说缓存层是完全可行的(只要纯数据集保留在那里)。

In terms of an abstract set of thoughts that my team operates by: if it can be trivially derived, do it in the transformer which is fed to connect( transform, bind )( Widget ); 根据我的团队操作的一组抽象概念:如果它可以通过简单的推导,在变换器中进行connect( transform, bind )( Widget ); .

If it can't be trivially derived, then caching it makes a lot of sense. 如果它不能简单地得出,那么缓存它就很有意义。

Great examples of this are where you may have 8000 raw product results, and then filter sliders, which operate on all sorts of data within a result. 很好的例子是你可能有8000个原始产品结果,然后过滤滑块,它们对结果中的各种数据进行操作。
You are going to want to keep a list of filteredResults so that you don't have to keep recalculating that on the fly. 您将要保留一个filteredResults列表,以便您不必在运行中重新计算。

Changing the page number of the view, though, shouldn't require rerunning all of those expensive filter operations (ie: in the transform), but rather just choose which view subset is sliced from the list of all already-filtered results. 但是,更改视图的页码不应该要求重新运行所有这些昂贵的过滤操作(即:在转换中),而只需从所有已过滤结果的列表中选择切片的视图子集。

It's one step further than what you're asking, but my one other suggestion would be "organizing by UI": be careful that you rotate common data out of "page" or "api" specific branches of the tree, and move them to a common place, if they are indeed common things. 它比你要求的更进一步,但我的另一个建议是“按UI组织”:小心你将公共数据从树的“页面”或“api”特定分支中旋转出来,并将它们移动到一个共同的地方,如果它们确实是常见的东西。

Having to mutate an object in two different places, to stay in sync with one another would be painful. 必须在两个不同的地方改变一个对象,以保持彼此同步将是痛苦的。

{
  searchPage: { user },
  landingPage: { user },
  checkoutPage: { user }
}

To match the UI is going to be very painful. 匹配UI将是非常痛苦的。

So... transform what you can sanely derive, cache what you can't, rotate what's common to be closer to the root. 所以...转换你可以理所当然地得到的东西,缓存你不能的东西,旋转更接近根的常见东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM