为什么此代码同时使用useMemo和createSelector?

时间:2020-06-18 13:14:52

标签: javascript reactjs redux memoization

The React-Redux documentation provides this example表示何时在多个组件实例中使用选择器并取决于组件的prop。

public String signUp(@RequestBody Usermodel user) {
        if(userRepository.findByUsername(user.getUsername())==null) {
            userRepository.save(user);
            return "Success";
        }
        else{
            return "Username Already Exsist";
        }
    }

在函数import React, { useMemo } from 'react' import { useSelector } from 'react-redux' import { createSelector } from 'reselect' const makeNumOfTodosWithIsDoneSelector = () => createSelector( state => state.todos, (_, isDone) => isDone, (todos, isDone) => todos.filter(todo => todo.isDone === isDone).length ) export const TodoCounterForIsDoneValue = ({ isDone }) => { const selectNumOfTodosWithIsDone = useMemo( makeNumOfTodosWithIsDoneSelector, [] ) const numOfTodosWithIsDoneValue = useSelector(state => selectNumOfTodosWithIsDone(state, isDone) ) return <div>{numOfTodosWithIsDoneValue}</div> } export const App = () => { return ( <> <span>Number of done todos:</span> <TodoCounterForIsDoneValue isDone={true} /> <span>Number of unfinished todos:</span> <TodoCounterForIsDoneValue isDone={false} /> </> ) } 中,为什么作者用TodoCounterForIsDoneValue包装makeNumOfTodosWithIsDoneSelector?我对useMemo中的createSelector的理解是,它会生成一个记住的选择器,那么“双重”记住该选择器的目的是什么?

2 个答案:

答案 0 :(得分:3)

因为每个组件都需要其自己的选择器实例才能实现正确的备注行为。如果许多组件使用相同的选择器实例,并且每个组件使用各自不同的参数(例如selectThingById(state, props.itemId)),则选择器永远不会记住正确的信息。通过为每个组件创建一个唯一的实例,每个选择器可以传递其自己的单独的arg并获得一致的备注。

答案 1 :(得分:0)

与问题稍微无关,但我认为在这种情况下,我们可以使用 useCallback 来获得相同的结果,而无需在 makeNumOfTodosWithIsDoneSelector 中添加额外的函数层。

import React, { useCallback } from 'react'
import { useSelector } from 'react-redux'
import { createSelector } from 'reselect'

const makeNumOfTodosWithIsDoneSelector = 
  createSelector(
    state => state.todos,
    (_, isDone) => isDone,
    (todos, isDone) => todos.filter(todo => todo.isDone === isDone).length
  )

export const TodoCounterForIsDoneValue = ({ isDone }) => {
  const selectNumOfTodosWithIsDone = useCallback(
    makeNumOfTodosWithIsDoneSelector,
    []
  )

  const numOfTodosWithIsDoneValue = useSelector(state =>
    selectNumOfTodosWithIsDone(state, isDone)
  )

  return <div>{numOfTodosWithIsDoneValue}</div>
}

export const App = () => {
  return (
    <>
      <span>Number of done todos:</span>
      <TodoCounterForIsDoneValue isDone={true} />
      <span>Number of unfinished todos:</span>
      <TodoCounterForIsDoneValue isDone={false} />
    </>
  )
}