目录

一、createSelector

二、useMemo

三、主要区别

四、使用建议

使用 createSelector 的情况:

使用 useMemo 的情况:

五、组合使用

六、总结

七、createSelector使用案例


createSelector 和 useMemo 都是用于性能优化的记忆化(memoization)工具,但它们在用途、使用场景和实现机制上有重要区别:

一、createSelector

(Redux Toolkit/Reselect)

官网文档:https://redux.js.org/usage/deriving-data-selectors#createselector-overview

主要用于 Redux store state 的派生数据计算:

import { createSelector } from '@reduxjs/toolkit'

const selectUsers = state => state.users
const selectFilters = state => state.filters

// 创建记忆化的selector
export const selectFilteredUsers = createSelector(
  [selectUsers, selectFilters],
  (users, filters) => {
    // 只有当 users 或 filters 改变时才重新计算
    return users.filter(user => 
      user.name.includes(filters.search) && 
      user.active === filters.activeOnly
    )
  }
)

// 在组件中使用
const filteredUsers = useSelector(selectFilteredUsers)

二、useMemo

(React Hook)

主要用于 组件内部 的昂贵计算:

import { useMemo } from 'react'

function UserList({ users, filters }) {
  const filteredUsers = useMemo(() => {
    // 只有当 users 或 filters 改变时才重新计算
    return users.filter(user => 
      user.name.includes(filters.search) && 
      user.active === filters.activeOnly
    )
  }, [users, filters])

  return <div>{/* 渲染 filteredUsers */}</div>
}

三、主要区别

特性 createSelector useMemo
使用场景 Redux state 派生数据 组件内部计算
依赖来源 Redux store state 组件 props/state
记忆化范围 全局(整个应用) 组件实例级别
重新计算时机 输入selector结果变化时 依赖数组变化时
缓存策略 默认浅比较,可自定义 引用比较(Object.is)
测试 易于单独测试 需要组件测试

四、使用建议

使用 createSelector 的情况:
  • 从 Redux store 派生复杂数据

  • 多个组件需要相同的派生数据

  • 数据转换逻辑复杂或计算昂贵

// 推荐:复杂的Redux数据转换
export const selectUserStats = createSelector(
  [selectUsers],
  (users) => ({
    total: users.length,
    active: users.filter(u => u.active).length,
    inactive: users.filter(u => !u.active).length
  })
)
使用 useMemo 的情况:
  • 组件内部的昂贵计算

  • 基于 props 或本地 state 的派生数据

  • 优化子组件重渲染

// 推荐:组件内部计算
function Chart({ data, config }) {
  const processedData = useMemo(() => {
    return data.map(item => ({
      ...item,
      value: item.value * config.multiplier
    }))
  }, [data, config])

  return <LineChart data={processedData} />
}

五、组合使用

两者可以结合使用以获得最佳性能:

// Redux selector - 第一层记忆化
export const selectProcessedData = createSelector(
  [selectRawData],
  (rawData) => rawData.map(processRawData)
)

// 组件内 - 第二层记忆化
function DataVisualization() {
  const processedData = useSelector(selectProcessedData)
  const [sortOrder, setSortOrder] = useState('asc')
  
  const sortedData = useMemo(() => {
    return [...processedData].sort((a, b) => 
      sortOrder === 'asc' ? a.value - b.value : b.value - a.value
    )
  }, [processedData, sortOrder])

  return <DataTable data={sortedData} />
}

六、总结

createSelector 用于 Redux 状态管理的记忆化,而 useMemo 用于 React 组件内部的记忆化。根据数据来源和使用场景选择合适的工具。

七、createSelector使用案例

import { createSelector } from 'reselect'
 
`输入选择器:从状态中提取原始数据`
const selectUser = (state) => state.user       【state.user 是 Redux Store 中的一个 slice】
const selectPosts = (state) => state.posts     【state.posts 是 Redux Store 中的一个 slice】
 
`Reselect 的 createSelector 会按顺序将 输入选择器的返回值,作为参数传递给转换函数。
 因此,转换函数中的
   user  对应 selectUser的返回值(即state.user)
   posts 对应 selectPosts的返回值(即state.posts)`
const selectUserData = createSelector(
    [selectUser, selectPosts],    `【输入选择器数组】`
    (user, posts) => ({           `【转换函数】`
        username: user.name,
        postCount: posts.length,
    })
)

组件中使用:

import { useSelector } from 'react-redux'
import { selectUserData } from './selectors'
 
const Component = () => {
    const { username, postCount } = useSelector(selectUserData)
     
    return (
        <div>
            <h3>{username}</h3>
            <p>Posts: {postCount}</p>
        </div>
    )
}

到此!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐