web-dev-qa-db-fra.com

Que sont les sélecteurs dans Redux?

J'essaie de suivre ce code in redux-saga

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

Ce qui est ensuite utilisé dans la saga comme this :

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

Ce réducteur getUser (même s'il s'agit d'un réducteur) est très différent de ce à quoi je m'attendrais normalement d'un réducteur.

Quelqu'un peut-il expliquer ce qu'est un sélecteur et comment getUser est un réducteur et comment il s'inscrit dans redux-saga?

39
dagda1

getUser n'est pas un réducteur, c'est en fait un sélecteur, c'est-à-dire une fonction qui sait comment extraire une donnée spécifique du magasin.

Les sélecteurs fournissent une couche supplémentaire telle que, si vous modifiez la structure de votre magasin et que tout à coup votre users ne soit plus à state.entities.users mais à state.users.objects.entities (ou autre), il vous suffit alors de mettre à jour le sélecteur getUser dans votre application où vous faisiez référence à l'ancien emplacement.

Cela les rend particulièrement utiles pour refactoriser votre magasin Redux.

57
horyd

Les sélecteurs sont des getters pour l'état redux. Comme les accesseurs, les sélecteurs encapsulent la structure de l'état et sont réutilisables. Les sélecteurs peuvent également calculer des propriétés dérivées. 

Vous pouvez écrire des sélecteurs, tels que ceux que vous avez vus dans redux-saga. Par exemple:

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

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

etc...

Vous pouvez également utiliser reselect , qui est une simple bibliothèque de «sélecteur» pour Redux, qui mémorise les sélecteurs pour les rendre plus efficaces.

12
Ori Drori

Les sélecteurs sont des fonctions qui prennent l'état Redux en tant qu'argument et renvoient certaines données à transmettre au composant.

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

Pourquoi devrait-il être utilisé?

  1. L'une des principales raisons est d'éviter les données dupliquées dans Redux.
  2. La forme de votre objet de données ne cesse de varier au fur et à mesure de la croissance de votre application. Plutôt que d’apporter des modifications à tous les composants associés, il est fortement recommandé/plus facile de modifier les données en un seul endroit.
  3. Les sélecteurs doivent être proches des réducteurs car ils fonctionnent dans le même état. Il est plus facile pour les données de rester synchronisées.

L'utilisation de resélectionner aide à mémoriser les données, ce qui signifie que lorsque la même entrée est transmise à la fonction, le résultat précédent est renvoyé au lieu d'être recalculé à nouveau. Cela améliore donc les performances de votre application.

1
CodeZombie
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>)
    }
}}

mais vous pouvez utiliser le sélecteur

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


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


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

Le problème principal est que ce composant utilise tous les utilisateurs: state.user et que tout changement d'utilisateur (etc isAdmin, isAuth, access) exécute la restitution de ce composant qui n'a besoin que d'une partie de ce magasin - access !!! 

Dans Redux, chaque fois qu'une action est appelée n'importe où dans l'application, tous les composants montés et connectés appellent leur mapStateToProps une fonction. C'est pourquoi Reselect est génial. Il va simplement retourner le résultat mémoisé si rien n'a changé.

Dans le monde réel, vous aurez probablement besoin de la même partie de votre objet d'état dans plusieurs composants.

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

La fonction createSelector fournie par Reselect implémente le moyen le plus simple de dériver un sélecteur à partir de sélecteurs précédents. Le cas d'utilisation le plus simple consiste à dériver un sélecteur d'un seul autre sélecteur. Dans ce cas, les paramètres à créerSélecteur sont le sélecteur d’entrée et une fonction transformant le résultat de ce sélecteur en résultat du nouveau sélecteur. Par exemple

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

Cela équivaut à (ignorer la mémorisation):

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

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

La fonction createSelector peut combiner des données provenant de plusieurs sélecteurs ainsi que d'un seul sélecteur. Nous pouvons transmettre n'importe quel nombre de sélecteurs à createSelector, et leurs résultats seront transmis à la fonction transmise comme argument final. Pour un exemple (quelque peu artificiel):

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

est équivalent à

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

le modèle courant lors de l'écriture de fonctions mapStateToProps avec des sélecteurs consiste à renvoyer un objet avec chaque clé stockant le résultat d'un sélecteur particulier. La fonction d’assistance createStructuredSelector dans Reselect nous permet d’écrire ce modèle avec le minimum requis. Par exemple, si nous écrivons

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

c'est équivalent à

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

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

0
zloctb