redux 使用带有参数的重新选择选择器

laximzn5  于 2023-06-23  发布在  其他
关注(0)|答案(7)|浏览(135)

如何将附加参数传递给组合选择器?我在努力
·获取数据
·过滤数据
·通过myValue将自定义值添加到我的数据集/组数据

export const allData = state => state.dataTable
export const filterText = state => state.filter.get('text')

export const selectAllData = createSelector(
  allData,
  (data) => data
)

export const selectAllDataFiltered = createSelector(
  [ selectAllData, filterText ],
  (data, text) => {
    return data.filter(item => {
      return item.name === text
    })
  }
)

export const selectWithValue = createSelector(
  [ selectAllDataFiltered ],
  (data, myValue) => {
    console.log(myValue)
    return data
  }
)

let data = selectWithValue(state, 'myValue')

console.log(myValue)返回undefined

c7rzv4ha

c7rzv4ha1#

更新日期:2022年2月16日
**Reselect 4.1中的新解决方案:**查看详情

// selector.js
const selectItemsByCategory = createSelector(
  [
    // Usual first input - extract value from `state`
    state => state.items,
    // Take the second arg, `category`, and forward to the output selector
    (state, category) => category
  ],
  // Output selector gets (`items, category)` as args
  (items, category) => items.filter(item => item.category === category)
);

// App.js
const items = selectItemsByCategory(state, 'javascript');
// Another way if you're using redux hook:
const items = useSelector(state => selectItemsByCategory(state, 'javascript'));

更新日期:2021年3月6日
**Reselect的解决方案:**详见

// selector.js
import { createSelector } from 'reselect'
import memoize from 'lodash.memoize'

const expensiveSelector = createSelector(
  state => state.items,
  items => memoize(
    minValue => items.filter(item => item.value > minValue)
  )
)

// App.js
const expensiveFilter = expensiveSelector(state)
// Another way if you're using redux:
// const expensiveFilter = useSelector(expensiveSelector)

const slightlyExpensive = expensiveFilter(100)
const veryExpensive = expensiveFilter(1000000)

旧:

这是我的方法。创建一个带参数的函数并返回reselect

export const selectWithValue = (CUSTOM_PARAMETER) => createSelector(
  selectAllDataFiltered,
  (data) => {
    console.log(CUSTOM_PARAMETER)
    return data[CUSTOM_PARAMETER]
  }
)

const data = selectWithValue('myValue')(myState);
jm2pwxwz

jm2pwxwz2#

这里有一个最新的useSelector钩子。
重要的是从输入选择器获取参数。输入选择器的第二个参数是我们如何得到它的。
选择器看起来是这样的

const selectNumOfTodosWithIsDoneValue = createSelector(
  (state) => state.todos,
  (_, isDone) => isDone, // this is the parameter we need
  (todos, isDone) => todos.filter((todo) => todo.isDone === isDone).length
)

下面是我们如何使用useSelector钩子提取值,

export const TodoCounterForIsDoneValue = ({ isDone }) => {
  const NumOfTodosWithIsDoneValue = useSelector((state) =>
    selectNumOfTodosWithIsDoneValue(state, isDone)
  )

  return <div>{NumOfTodosWithIsDoneValue}</div>
}

另外,尽可能将第二个参数(isDone)保持为primitive values(字符串,数字等)。因为reselect只在输入选择器值更改时运行输出选择器。此更改通过浅比较来检查,对于Object和Array等引用值,该值总是为false。
参考文献:

  1. www.example.com https://react-redux.js.org/next/api/hooks#using-memoizing-selectors
  2. https://flufd.github.io/reselect-with-multiple-parameters/
  3. https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/
hxzsmxv2

hxzsmxv23#

您的问题的答案在这里的常见问题解答中有详细说明:https://github.com/reactjs/reselect#q-how-do-i-create-a-selector-that-takes-an-argument
简而言之,reselect不支持传递给选择器的任意参数。推荐的方法是,不传递参数,而是将相同的数据存储在Redux状态中。

y0u0uwnf

y0u0uwnf4#

如何从选择器返回一个函数?getFilteredToDos就是一个例子

// redux part
const state = {
  todos: [
    { state: 'done',     text: 'foo' },
    { state: 'time out', text: 'bar' },
  ],
};

// selector for todos
const getToDos = createSelector(
  getState,
  (state) => state.todos,
);

// selector for filtered todos
const getFilteredToDos = createSelector(
  getToDos,
  (todos) => (todoState) => todos.filter((toDo) => toDo.state === todoState);
);

// and in component
const mapStateToProps = (state, ownProps) => ({
  ...ownProps,
  doneToDos: getFilteredToDos()('done')
});
xj3cbfub

xj3cbfub5#

这在Reselect文档中的“在选择器中访问React Props”中有所介绍:

import { createSelector } from 'reselect'

const getVisibilityFilter = (state, props) =>
  state.todoLists[props.listId].visibilityFilter

const getTodos = (state, props) =>
  state.todoLists[props.listId].todos

const makeGetVisibleTodos = () => {
  return createSelector(
    [ getVisibilityFilter, getTodos ],
    (visibilityFilter, todos) => {
      switch (visibilityFilter) {
        case 'SHOW_COMPLETED':
          return todos.filter(todo => todo.completed)
        case 'SHOW_ACTIVE':
          return todos.filter(todo => !todo.completed)
        default:
          return todos
      }
    }
  )
}

export default makeGetVisibleTodos
const makeMapStateToProps = () => {
  const getVisibleTodos = makeGetVisibleTodos()
  const mapStateToProps = (state, props) => {
    return {
      todos: getVisibleTodos(state, props)
    }
  }
  return mapStateToProps
}

在这种情况下,传递给选择器的props是传递给React组件的props,但props可以来自任何地方:

const getVisibleTodos = makeGetVisibleTodos()

const todos = getVisibleTodos(state, {listId: 55})

查看下面的Reselect类型:

export type ParametricSelector<S, P, R> = (state: S, props: P, ...args: any[]) => R;
export function createSelector<S, P, R1, T>(
  selectors: [ParametricSelector<S, P, R1>],
  combiner: (res: R1) => T,
): OutputParametricSelector<S, P, T, (res: R1) => T>;

我们可以看到,props的类型没有限制(ParametricSelect中的P类型),所以它不需要是object

8oomwypt

8oomwypt6#

下面是一个带有参数的选择器,它是真正记忆化的(除了最后一次调用,不像Reselect中的createSelector):

const pokemon = useSelector(selectPokemonById(id));
import memoize from 'lodash.memoize';
import { createSelector } from '@reduxjs/toolkit';

const selectPokemonById = memoize((id) => {
  return createSelector(
    (state) => state.pokemons,
    (pokemons) => {
      const pokemon = pokemons.find(id => p.id === id);
      return pokemon;
    }
  )
})

createSelector的问题是它只记住了最后一个调用的参数(https://redux.js.org/usage/deriving-data-selectors#createselector-behavior)
createSelector只存储最近的参数集。这意味着,如果你用不同的输入重复调用选择器,它仍然会返回一个结果,但它必须不断地重新运行输出选择器来产生结果:
为了克服这个问题,我们的想法是使用lodash的memoize函数来记忆给定参数的选择器。
更多信息:https://dev.to/tilakmaddy_68/how-to-memoize-correctly-using-redux-reselect-20m7

5uzkadbs

5uzkadbs7#

另一个选择:

const parameterizedSelector = (state, someParam) => createSelector(
  [otherSelector],
  (otherSelectorResult) => someParam + otherSelectorResult
);

然后用像

const mapStateToProps = state => ({
  parameterizedSelectorResult: parameterizedSelector(state, 'hello')
});

我不确定在这种情况下的记忆/性能,但它的工作。

相关问题