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

问题描述 投票:0回答:7

如何将附加参数传递给组合选择器?我正在努力

• 获取数据

• 过滤数据

• 通过 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

javascript reactjs ecmascript-6 redux reselect
7个回答
61
投票

更新日期:2023 年 12 月 4 日

与 4.1 相比没有变化,但是 使用 Typescript 更新了 5.0.0 版本的文档。请阅读文档以了解有关特殊情况的更多详细信息。

// selector.ts const selectAvailableItems = createSelector( [ // First input selector extracts items from the state (state: RootState) => state.items, // Second input selector forwards the category argument (state: RootState, category: string) => category, // Third input selector forwards the ID argument (state: RootState, category: string, id: number) => id ], // Output selector uses the extracted items, category, and ID (items, category, id) => items.filter(item => item.category === category && item.id !== id) ) interface RootState { items: { id: number category: string vendor: { id: number; name: string } }[] // ... other state properties ... }
// App.tsx
const items = selectAvailableItems(state, 'javascript', 10);
// Another way if you're using redux hook:
const items = useSelector(state => selectAvailableItems(state, 'javascript', 10));

更新日期: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);
    

17
投票
这是带有最新

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

)保留为
原始值(字符串、数字等)。 因为,reselect 仅在输入选择器值更改时运行输出选择器。 此更改是通过浅比较来检查的,对于对象和数组等参考值来说,浅比较始终为 false。

参考资料:

  1. 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/

14
投票
您的问题的答案在此处的常见问题解答中有详细说明:

https://github.com/reactjs/reselect#q-how-do-i-create-a-selector-that-takes-an-argument

简而言之,reselect 不支持传递给选择器的任意参数。推荐的方法是将相同的数据存储在 Redux 状态中,而不是传递参数。


8
投票
从选择器返回一个函数怎么样?

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') });
    

1
投票
这在

Accessing React Props in Selectors: 下的重新选择文档中进行了介绍

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})
查看以下重新选择的类型:

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>;
我们可以看到道具的类型没有限制(

P

中的
ParametricSelect
类型),所以它不需要是
object


0
投票
这是一个带有真正记忆参数的选择器(超越最后一次调用,与 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


-1
投票
另一种选择:

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

然后使用like

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

虽然我不确定这种情况下的记忆/性能,但它确实有效。

© www.soinside.com 2019 - 2024. All rights reserved.