【问题标题】:How is state passed to selectors in a react-redux app?状态如何传递给 react-redux 应用程序中的选择器?
【发布时间】:2017-01-10 13:37:08
【问题描述】:

我遇到了一个示例,其中 mapStateToProps 函数正在使用记忆。我只是想知道如何将“状态”参数传递给记忆选择器。在查看了 reselect 和 redux 的文档之后,似乎 mapStateToProps 可以返回一个接受状态作为其参数的函数,并且连接装饰器可能是将状态传递给它但不确定的那个。有人可以解释一下吗?

views/tracklist/index.js

const mapStateToProps = createSelector(
  getBrowserMedia,
  getPlayerIsPlaying,
  getPlayerTrackId,
  getCurrentTracklist,
  getTracksForCurrentTracklist,
  (media, isPlaying, playerTrackId, tracklist, tracks) => ({
    displayLoadingIndicator: tracklist.isPending || tracklist.hasNextPage,
    isMediaLarge: !!media.large,
    isPlaying,
    pause: audio.pause,
    pauseInfiniteScroll: tracklist.isPending || !tracklist.hasNextPage,
    play: audio.play,
    selectedTrackId: playerTrackId,
    tracklistId: tracklist.id,
    tracks
  })
);

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Tracklist);

core/tracklists/selectors.js

export function getCurrentTracklist(state) {
//  console.log(state);
  let tracklists = getTracklists(state);
  return tracklists.get(tracklists.get('currentTracklistId'));
}

export const getTracksForCurrentTracklist = createSelector(
  getCurrentPage,
  getCurrentTrackIds,
  getTracks,
  (currentPage, trackIds, tracks) => {
    return trackIds
      .slice(0, currentPage * TRACKS_PER_PAGE)
      .map(id => tracks.get(id));
  }
);

【问题讨论】:

    标签: javascript reactjs redux reselect


    【解决方案1】:

    当我们使用 react-redux 中的 Connect 组件时,状态如何传递给选择器的概述

    什么是选择器?

    选择器从源中提取数据子集。

    让我们将 Redux 存储视为我们的“前端数据库”。为此,在数据库中,如果要提取总数据的子集,则执行查询。以类似的方式,选择器是我们对 Redux 存储的查询。

    在最简单的情况下,选择器可以只返回整个商店的状态。

    重新选择文档为我们提供了三个很好的使用选择器的理由

    • 选择器可以计算派生数据,允许 Redux 存储 最小可能状态。
    • 选择器很有效。选择器不是 除非其中一个参数发生变化,否则会重新计算。
    • 选择器是 可组合的。它们可以用作其他选择器的输入。

    什么是高阶组件?

    高阶组件是接受现有组件并返回新组件的函数。

    Connect 是一个被赋予选择器的高阶组件

    取自thisbright gist,它很好地解释了连接。

    connect() 是一个将 Redux 相关的 props 注入到你的 组件。

    Connect 是一个高阶组件,它使我们的 React 组件了解 Redux 存储。当我们调用 connect 时,我们可以传递 mapStateToProps 和 mapDispatchToProps。这些函数定义了我们的新组件连接到 redux 存储的方式

    我们可以通过将 mapStateToProps 函数作为参数传递给它访问状态。

    我们还可以通过 mapDispatchToProps 将动作创建者绑定到 store.dispatch。这样做的好处是我们不需要传递整个 store 来让组件可以访问 store.dispatch 以便组件可以调度自己的 Redux 操作。

    我们传递给 Connect 的 mapStateToProps 函数是一个选择器

    来自 react-redux 文档

    mapStateToProps 函数接受整个函数的单个参数 Redux 存储的状态并返回一个作为 props 传递的对象。这是 通常称为选择器。

    将 mapStateToProps 返回的对象视为我们对 Redux 存储的查询结果。结果

    mapStateToProps 函数通常应该返回一个普通对象。

    调用 mapStateToProps 的结果通常是一个普通对象,表示我们从 redux 存储中提取的数据。

    高阶 Connect 组件允许我们通过将来自这个新对象的数据与组件的现有道具合并来扩展现有组件的功能。

    由于选择器只是函数,我们也可以使用 connect 组件将它们连接到 Redux 存储。

    但是在某些情况下我们可以返回一个函数。我们为什么要这样做?

    通过在mapStateToProps中return一个函数,我们可以劫持组件的渲染周期并优化性能

    在您需要对渲染进行更多控制的高级场景中 性能方面,mapStateToProps() 也可以返回一个函数。在这个 在这种情况下,该函数将用作特定的 mapStateToProps() 组件实例。这允许您进行每个实例的记忆。

    通过将 mapStateToProps 函数作为参数传递给我们的高阶组件,我们的连接组件将在 Redux 存储中的某些状态发生更改时更新。

    如果这些更新非常频繁或状态树很大,那么重新选择库很有用,因为它允许我们使用 memoized 选择器。

    这个花哨的词意味着选择器调用的结果被存储起来,以防需要再次检索。

    因此,如果 mapStatesToProps 返回一个普通对象而不是函数,那么每当我们的商店状态发生变化时,我们就会为我们的组件提供新的道具。???

    将选择器连接到商店

    如果您使用的是 React Redux,您可以在 mapStateToProps() 中将选择器作为常规函数调用:

    import { getVisibleTodos } from '../selectors'
    
    const mapStateToProps = (state) => {
      return {
        todos: getVisibleTodos(state)
      }
    }
    

    跨多个组件共享选择器

    在使用重选库时,我们可以像组件一样为重选选择器提供道具。这允许我们在多个组件之间共享选择器。

    假设我们有多个 toDo 列表,每个列表都有自己的 ID。我们仍然会为每个待办事项列表实例使用相同的 getVisibleTodos 选择器,但只需传递不同的 id 作为道具。

    但是,问题在于 createSelector 仅在其参数集与其先前的参数集相同时才返回缓存值。

    reselect 文档指出我们可以通过在 mapStateToProps 中返回一个函数来克服这个限制:

    为了在多个组件之间共享一个选择器并保留 memoization,组件的每个实例 需要它自己的选择器私有副本。 如果提供给 connect 的 mapStateToProps 参数返回一个函数 而不是一个对象,它将被用来创建一个个体 每个容器实例的 mapStateToProps 函数。

    通过在 mapStateToProps 中返回一个函数,我们可以克服这个限制,并且 memoization 可以正常工作。

    更详细的解释见this

    【讨论】:

    • 如果有人能指出这个答案最后一部分的改进,那就太好了。
    【解决方案2】:

    就是这么简单:举个例子,我有一个像这样的ma​​pStateToProps

    function mapStateToProps(state) {
      return {
        categoryHistory: getCategoryHistory(state,'extended')
      }
    }
    

    然后我创建了一个像这样的选择器

    export const getCategoryHistory = (state, type) => createSelector([getTaxonomy, selectedCategoryID], (categories, categoryID) => categories.getIn([type, categoryID]) || [])(state)
    

    解决方案是调用 createSelector() 传递 state 作为参数:

    createSelector()(state)

    在选择器中你可以使用你想要传递的所有参数。

    【讨论】:

      【解决方案3】:

      在您提到的情况下, mapStateToProps 是一个接收状态和返回对象的函数。当您将 mapStateToProps 传递给 connect 时,您传递了一个函数,该函数接受 connect 提供的状态作为其参数。

      createSelector 创建一个可以接收状态和返回对象的函数。因此,您可以将其分配给 mapStateToProps 并将其传递给 connect。

      在文档中,您通常会找到以下内容:

      const mapStateToProps = (state) => {
          whatever code
      }
      

      export default connect(mapStateToProps, mapDispatchToProps)(Component)
      

      mapStateToProps 接受 connect 提供的 state 参数。

      但是,可以让 mapStateToProps 成为一个选择器,如下所示:

      const mapStateToProps = createSelector(
          whatever code
      )
      

      这是因为 createSelector 可以采取如下状态:

      createSelector(whatever code)(state)
      

      并返回一个对象,就像您在文档中找到 mapStateToProps 所做的那样。

      【讨论】:

        猜你喜欢
        • 2017-01-26
        • 1970-01-01
        • 2019-08-16
        • 2016-11-26
        • 1970-01-01
        • 1970-01-01
        • 2016-08-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多