【问题标题】:Duplicating state in Redux在 Redux 中复制状态
【发布时间】:2018-01-23 03:38:39
【问题描述】:

假设您有一个使用 Redux 并具有一些功能的图书应用程序:

  • 买书
  • 有书籍的愿望清单
  • 维护您拥有的图书列表
  • 向朋友发送推荐
  • 审阅书籍

现在让我们假设所有这些不同的模块,并且所有这些模块的一个共同功能是搜索书籍的能力(即搜索要购买的书籍、​​要添加到愿望清单的书籍、要评论的书籍等)。

这些搜索结果将存储在状态树的多个切片中。

状态树的示例可能如下所示:

{
  bookStore: {
    booksSearchResults: [],
    ...,
  },
  wishlist: {
    booksSearchResults: [],
    ...,
  },
  reviews: {
    newReview: {
      booksSearchResults: [],
      ...,
    },
    ...
  },
  ...
}

在管理此类事情方面是否有任何最佳做法?拥有一个booksSearch 状态切片并通过共享组件进行管理是不是很简单?

如果您可能需要在同一屏幕上的多个位置搜索书籍(即,除了应用程序主要部分中的搜索组件之外,您可能在导航栏中具有自动完成搜索功能)?

是否有另一种方法可以重用搜索逻辑并以某种方式更新状态的不同部分(如果是,是否存在实现此目的的方法)?

【问题讨论】:

    标签: architecture redux


    【解决方案1】:

    我有两条建议给你:

    1. 规范您的商店。
    2. 不要将搜索结果存储在 redux 中。

    标准化

    这是有据可查的,所以我不会在这里深入探讨。可以说,规范化您的商店将是灵活的,并帮助您推理您的应用程序。将您的商店想象成一个服务器端数据库,它比根据您的视图定制状态的每个部分更具可重用性。

    您可以为您的应用执行此操作的一种方法:

    {
      books: { 
        bookId: { 
          bookDetails,
          reviews: [ reviewId ],
          ownedBy: [ userId ],
          wishlistedBy: [ userId ],
          recommendations: [ recommendationId ]
        }
      },
      users: {
        userId: { 
          userDetails,
          reviews: [ reviewId ],
          wishlist: [ bookId ],
          ownedBooks: [ bookId ],
          friends: [ userId ],
          sentRecommendations: [ recommendationId ],
          receivedRecommendations: [ recommendationId ]
        }
      },
      reviews: {
        reviewId: {
          bookId,
          userId,
          reviewDetails
        }
      },
      recommendations: {
        recommendationId: {
          sender: userId,
          recipient: userId,
          bookId,
          recommendationDetails
        }
      }
    }
    

    您可能不需要所有这些关系,所以不要觉得您必须实现所有这些。但是从与此类似的基础开始,以后添加功能会容易得多。

    资源:

    在哪里放置搜索结果

    搜索结果更多的是视图细节而不是数据问题。您可能需要存储搜索的历史记录,在这种情况下,您可以为搜索添加 reducer:

    {
      searches: [
        {
          searchTerm,
          searchDetails
        }
      ]
    }
    

    但即使在这种情况下,我也不认为我会存储搜索结果。在某些情况下,存储结果会限制功能。

    1. 当用户搜索时,会添加一本新书,除非您重新运行搜索,否则您将无法在后续搜索中找到新书(这否定了存储结果的用处)。
    2. 搜索需要快速并且存储结果只会加速重复搜索(这可能不太常见)。

    因此,我将结果视为视图细节——或者,正如 James K. Nelson 所说,“控制状态”(阅读:The 5 Types of React Application State)。您的问题没有说明您使用的是哪个视图库(如果有),但无论您是否使用 React,这里的概念都应该适用。

    搜索结果应按视图计算。视图将接收用户输入,可能会获取数据(将添加到存储中),在 Redux 状态上运行一些过滤器功能,并显示结果。

    【讨论】:

      【解决方案2】:

      redux 应用程序中的可重用组件有一个很好的模式,对您很有用。这是假设从 redux 的角度来看,搜索使用相同的 api 和逻辑以及逻辑的一个或多个可重用组件。

      在本例中,我将使用<AutoCompleteSearch /><FullSearch /> 作为 UI 组件,它们可以在应用程序甚至同一页面中出现多次。

      这里使用的模式是为每个组件分配一个唯一的道具,这里命名为searchId: string,例如<AutoCompleteSearch searchId="wishlist" />.

      然后组件在所有搜索相关操作的负载中传递这个 id,例如

      {
        type: SEARCH,
        payload: {
          term: "Harry Potter",
          searchId: "wishlist",
        }
      }
      

      搜索缩减器的结构是一个以searchId 为键的映射。 redux 状态示例:

      {
        wishlist: {
          inProgress: true,
          searchTerm: "Harry Potter",
          results: [],
        },
        reviews: {
          inProgress: false,
          searchTerm: "",
          results: [],
        },
      }
      

      reducer 然后选择要处理的状态部分:

      const reducer = (state, action) => {
        switch(action.type) {
          case SEARCH:
            return {
              ...state,
              [action.payload.searchId]: {
                inProgress: true,
                searchTerm: action.payload.searchTerm,
                results: [],
              }
            };
          default:
            return state;
        }
      

      有关使用此模式进行数据加载的现成库,请参阅redux-autoloader

      【讨论】:

        【解决方案3】:

        如果您能够重复使用搜索结果,即搜索查询相同或跨组件共享,那么您最好使用共享组件。如果不是,建议将搜索和搜索结果分开并与上下文相关。

        查看 Don 与他的待办事项示例分享的示例。他为 All TodosCompleted TodosActive Todos 创建了三个不同的列表。

        【讨论】:

          【解决方案4】:

          我认为答案取决于您的需要:

          1. 共享搜索 - 例如在任何上下文中搜索过的项目。
          2. 唯一搜索 - 例如在特定上下文中搜索的项目。

          如果您想通过第一种情况自动排序,我建议将所有搜索数组组合起来,并将数据存储在提供更多细节的对象中,例如 searchContext 等。 如果您想按第二种情况自动完成,则其他上下文的搜索结果不相关,因此建议对任何搜索上下文使用单独的数组。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-01-19
            • 2017-12-02
            • 1970-01-01
            • 1970-01-01
            • 2018-06-29
            • 2019-01-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多