55

我正在尝试遵循此代码redux-saga

export const getUser = (state, login) => state.entities.users[login]
export const getRepo = (state, fullName) => state.entities.repos[fullName]

然后像这样在传奇中使用它:

import { getUser } from '../reducers/selectors'

// load user unless it is cached
function* loadUser(login, requiredFields) {
  const user = yield select(getUser, login)
  if (!user || requiredFields.some(key => !user.hasOwnProperty(key))) {
    yield call(fetchUser, login)
  }
}

这个getUser减速器(它甚至是减速器)看起来与我通常期望的减速器看起来非常不同。

谁能解释一下选择器是什么,getUserreducer 是怎样的,以及它是如何适应 redux-saga 的?

4

4 回答 4

72

getUser不是reducer,它确实是一个选择器,也就是一个知道如何从store中提取特定数据的函数。

选择器提供了一个额外的层,这样如果你改变了你的商店结构并且突然间你users不再在state.entities.users,而是在state.users.objects.entities(或其他),那么你只需要更新getUser选择器,而不是你的应用程序中你正在制作的每个地方参考旧位置。

这使得它们在重构 Redux 存储时特别方便。

于 2016-07-30T13:24:18.070 回答
16

选择器是 redux 状态的吸气剂。像 getter 一样,选择器封装了状态的结构,并且是可重用的。选择器还可以计算派生属性。

您可以编写选择器,例如您在 redux-saga 中看到的选择器。例如:

const getUsersNumber = ({ users }) => users.length;

const getUsersIds = ({ users }) => users.map(({ id }) => id);

ETC...

您还可以使用reselect,这是一个简单的 Redux “选择器”库,它可以记忆选择器以提高它们的效率。

于 2016-07-30T13:26:25.523 回答
2

选择器是将 Redux 状态作为参数并返回一些数据以传递给组件的函数。

const getUserData = state => state.user.data;

为什么要使用它?

  1. 主要原因之一是避免 Redux 中的重复数据。
  2. 随着应用程序的增长,您的数据对象形状会不断变化,因此不要在所有相关组件中进行更改。建议/更容易在一个地方更改数据。
  3. 选择器应该靠近减速器,因为它们在相同的状态下运行。数据更容易保持同步。

使用重新选择有助于在将相同的输入传递给函数时记住数据含义,返回先前的结果而不是再次重新计算。因此,这可以提高您的应用程序性能。

于 2018-02-22T07:58:35.483 回答
2
function mapStateToProps (state) {
    return {
        user: state.user,
    }
}

initialState of reducer by user store
const initialState = {
  isAdmin:false,
  isAuth:false,
  access:[1,2,5]
};

class AppComp extends React.Component{
render(){
        const {user: { access:access}} = this.props;
        const rand = Math.floor(Math.random()*4000)
        return (<div>
            {`APP ${rand} `}
    <input type="button" defaultValue="change auth" onClick={this.onChangeUserAuth} />
        <p>TOTAL STATUS COUNT IS {access.length}</p>
        </div>)
    }
}}

但你可以使用选择器

var getUser = function(state) {
    return state.user
}


const getAuthProp = createSelector(
    getUser,
    (user) => user.access
);


function mapStateToProps (state) {
    return {
       // user: state.user,
        access: getAuthProp(state)
    }
}

主要问题是该组件使用所有用户:state.user 和用户的任何更改(等 isAdmin、isAuth、访问)运行重新渲染此组件,它只需要此存储的一部分 - 访问!!!

在 Redux 中,每当在应用程序的任何地方调用一个操作时,所有已挂载和连接的组件都会调用它们的 mapStateToProps 函数。这就是重新选择很棒的原因。如果没有任何变化,它只会返回记忆的结果。

在现实世界中,您很可能需要在多个组件中使用相同的状态对象部分。

https://medium.com/@parkerdan/react-reselect-and-redux-b34017f8194c

Reselect 提供的 createSelector 函数实现了从之前的选择器派生选择器的最基本方式。最简单的用例是从单个其他选择器派生选择器。在这种情况下,createSelector 的参数是输入选择器和将该选择器的结果转换为新选择器的结果的函数。例如

var getProducts = function(state) {
    return state.products
}


import {getProducts} from '../app/selectors'
import {createSelector} from 'reselect'

export const getProductTitles = createSelector(
    getProducts,
    (products) => products.map((product) => product.get('title'))
)

这相当于(忽略记忆):

import {getProducts} from '../app/selectors'

export const getProductTitles = (state) => {
    return getProducts(state).map((product) => product.get('title'))
}

createSelector 函数可以组合来自多个选择器以及来自单个选择器的数据。我们可以将任意数量的选择器传递给 createSelector,它们的结果将传递给作为最终参数传递的函数。对于一个(有些人为的)示例:

const isInCheckout = createSelector(
    getIsShippingPage,
    getIsBillingPage,
    getIsConfirmationPage,
    (isShipping, isBilling, isConfirmation) =>
        isShipping || isBilling || isConfirmation
)

相当于

const isInCheckout = (state) => {
    return (
        getIsShippingPage(state) ||
        getIsBilingPage(state) ||
        getIsConfirmationPage(state)
    )
}

使用选择器编写 mapStateToProps 函数时的常见模式是返回一个对象,其中每个键存储特定选择器的结果。Reselect 中的 createStructuredSelector 辅助函数让我们可以用最少的样板代码编写此模式。例如,如果我们写

const mapStateToProps = createStructuredSelector({
    title: getProductTitle,
    price: getProductPrice,
    image: getProductImage
})

它相当于

const mapStateToProps = (state) => {
    return {
        title: getProductTitle(state),
        price: getProductPrice(state),
        image: getProductImage(state)
    }
}

https://docs.mobify.com/progressive-web/0.15.0/guides/reselect/

于 2018-12-28T14:50:15.987 回答