状态管理方案的首选: Redux | 阅读文档后理解 (2)

141 阅读3分钟

性能优化

选择器

当仓库中一个 对象类型的 state 的一条属性改变时,当前页面下,访问过这个 state 的选择器会再次触发,因为仅仅是一条属性被改变,state 的指针并没有变化,但是访问过这个 state 且没有使用过变化的属性的选择器再次触发,从而重新渲染组件。

是否存在方法让选择器的输入不变时,输出缓存的输出呢

答案是 createSelector

createSelector 是一个来自于 reselect 库的函数,用于创建 memoized selector。Selector 是一个函数,它接受一个或多个 state 参数,并返回一个派生自 state 的值。通常情况下,selector 的计算是相对昂贵的,因为它们需要遍历整个 state 树,执行一系列转换操作才能得到最终的返回值。

为了避免不必要的重复计算,可以使用 createSelector 来创建一个 memoized selector。Memoized selector 会对输入参数进行缓存,只有在输入参数发生变化时才会重新计算值。这可以显著提高性能,特别是在处理大型 state 树时。

createSelector 的使用方式非常简单,只需要传入一个或多个 selector 函数和一个转换函数。转换函数接受所有输入 selector 的返回值作为参数,并返回一个计算出来的值。createSelector 会自动缓存输入参数和输出值,以便在下次调用时进行比较。

范式化

当我们使用范式化时,我们通常会将 store 中的数据组织成一个个实体对象。下面是一个示例,假设我们有一个包含多个用户和多个文章的博客应用程序,每个用户和文章都有唯一的 ID。

// 原始的 store 数据结构
const initialState = {
  users: {
    byId: {
      '1': { id: '1', name: 'Alice' },
      '2': { id: '2', name: 'Bob' },
      '3': { id: '3', name: 'Charlie' },
    },
    allIds: ['1', '2', '3'],
  },
  articles: {
    byId: {
      '4': { id: '4', title: 'First Article', author: '1' },
      '5': { id: '5', title: 'Second Article', author: '2' },
      '6': { id: '6', title: 'Third Article', author: '3' },
    },
    allIds: ['4', '5', '6'],
  },
}
​

在这个例子中,我们将用户和文章分别存储在 users 和 articles 实体对象中。每个实体对象都包含一个 byId 对象,其中键是实体的 ID,值是实体本身的属性。我们还添加了一个 allIds 数组,用于存储实体 ID 的顺序。

通过这种方式,我们可以在 store 中快速查找和更新每个用户和文章对象。例如,要查找 ID 为 '4' 的文章对象,我们可以使用以下代码:

const article = state.articles.byId['4']

范式化还可以帮助我们更容易地进行数据关联。例如,我们可以将每篇文章的 author 属性设置为对应的用户 ID。这样,我们可以使用以下代码查找某篇文章的作者:

const authorId = state.articles.byId['4'].author
const author = state.users.byId[authorId]
​

通过这种方式,我们可以在 store 中轻松地管理和查询关联的数据,从而使我们的应用程序更加灵活和高效。