如何使用 yield select 管理接受参数的选择器?

Posted

技术标签:

【中文标题】如何使用 yield select 管理接受参数的选择器?【英文标题】:How to manage a selector that accepts arguments with yield select? 【发布时间】:2021-12-22 00:55:23 【问题描述】:

我有一个 React 应用程序,我在其中使用 Redux 和 Redux-Saga 并 Reselect 作为选择器库(使用 Immer 来处理 Redux 状态的不变性)。我写这个问题是因为我想了解我处理带参数的选择器的方法是否完全正确。

我个人更喜欢避免在 sagas 中使用 yield select,因为我想保留中间件 not depend on the Store's state,但我的旧代码中包含带有 yield select 的 sagas。

下面是我必须编写的代码来实现我的选择器并将他调用到组件和传奇中。我从Reselec doc 获得了选择器实现。

// selectors.js: Selector implementation
const makeGetPerson = createSelector(
  getPersonsList,
  (state, id) => id,
  (persons, id) => persons.find((person) => person.id === id)
);

// components.js: if I have to use the selector into a component
const person = useSelector((state) => makeGetPerson(state, id))


// saga.js: if I have to use the selector into a saga
const persons = yield select(getPersonsList)
const person = persons.find((person) => person.id === id)

目前,我必须使用返回元素列表的选择器并手动过滤它们。有没有办法在 a saga 中做类似yield select((state) => getPersonsList(state, id)) 的事情?我还缺少其他方法吗?

【问题讨论】:

吹毛求疵:不要调用选择器makeGetPerson。 “make”前缀通常用于“选择器工厂”,每次调用时都会返回一个新的选择器实例。这不是“工厂”——它是选择器函数本身。就叫它getPersonselectPerson。有关详细信息,请参阅 Redux 文档 Deriving Data with Selectors 页面。 【参考方案1】:

select 效果创建器在选择器函数之后接受附加参数,然后将其发送到选择器本身,因此您可以这样做:

const person = yield select(makeGetPerson, id);

文档:https://redux-saga.js.org/docs/api/#selectselector-args

【讨论】:

谢谢!!我错过了文档中的那部分。【参考方案2】:

您也可以将 createSelectPersonById 设为咖喱:

const createSelectPersonById = id => createSelector(
  getPersonsList,
  (persons) => persons.find((person) => person.id === id)
);
// components
const person = useSelector(createSelectPersonById(id))
//saga
const person = yield select(createSelectPersonById(id));

在按 id 选择人员中,您只是返回状态而不是新对象,但如果您每次都可以在组件中使用 useMemo 时确实返回一个新对象,这样您就不会在分派不相关的操作时获得不必要的重新渲染:

//selector returning new object every time it is executed
const createSelectPersonById = (id) =>
  createSelector(getPersonsList, (persons) => 
    const person = persons.find(
      (person) => person.id === id
    );
    //returning a new object reference every time
    return 
      ...person,
      fullName:formatFullName(person)
    
  );
//in components
const selectPersonById = React.useMemo(
  ()=>createSelectPersonById(id),
  [id]//selector only re created when id changes
)
const person = useSelector(selectPersonById);
//in saga nothing changes, no need to memoize:
const person = yield select(createSelectPersonById(id));

更多关于我如何以及为什么在 React 中使参数化选择器成为咖喱的信息可以在 here 找到。

【讨论】:

curry 方法 + useMemo 可以工作,我没有考虑过。我感觉在为选择器重新选择的组件中使用 useMemo 有点多余。将 useSelector 与组件的回调语法一起使用,并将 yield select 与 varargs 用于 saga 可以帮助构建线性架构。你怎么看? @lucataglia I'm having the feeling that use the useMemo in the component having Reselect for the selector is a little redundant. 如果您的选择器返回一个新的引用(在您的代码示例中没有),则如果您有一个列表渲染并且每个组件都调用除非组件有自己的选择器,否则选择器具有不同的 id。 @lucataglia 我已经更新了 repo,试图更清楚地解释这一点:paremeterized and memoized selectors

以上是关于如何使用 yield select 管理接受参数的选择器?的主要内容,如果未能解决你的问题,请参考以下文章

yield的表示形式

yield()返回参数函数使用

Select2:如何允许用户从默认列表中选择但接受新字符串?

day4 使用yield实现单线程

ruby 疑难点之—— yield 和 yield self

如何让celery接受定制的参数