Maison > Questions et réponses > le corps du texte
Je construis un projet en utilisant Redux Toolkit et RTK Query et j'essaie d'obtenir des entrées de l'API. J'utilise la méthode de normalisation des données de createEntityAdapter car dans un certain composant, j'ai besoin des données sous forme de tableau, j'ai donc fini par utiliser un sélecteur. Maintenant, mon problème est que depuis que j'ai ajouté le filtre en tant que paramètre de la requête, mon sélecteur a cessé de fonctionner.
J'ai examiné des questions similaires ici comme : "Comment utiliser le sélecteur de requête RTK avec des paramètres ?", mais je suis trop stupide pour comprendre ce que je dois modifier. J'essaie de comprendre la documentation des requêtes RTK, mais je n'y parviens pas.
D'après la question ci-dessus, je sais que mon sélecteur doit également avoir des paramètres afin de savoir exactement quoi sélectionner, et que ce n'est pas un modèle recommandé, mais je n'arrive pas à comprendre comment le faire fonctionner.
Ma tranche d'entrée :
import { createSelector, createEntityAdapter } from '@reduxjs/toolkit' import { apiSlice } from './apiSlice' const entryAdapter = createEntityAdapter() const initialState = entryAdapter.getInitialState({ ids: [], entities: {}, }) export const entryApiSlice = apiSlice.injectEndpoints({ endpoints: (builder) => ({ initialState, getEntry: builder.query({ query: (filters) => ({ url: '/history', params: filters, }), transformResponse: (responseData) => { return entryAdapter.setAll(initialState, responseData) }, providesTags: (result, error, arg) => [ { type: 'Entry', id: 'LIST' }, ...result.ids.map((id) => ({ type: 'Entry', id })), ], }), addEntry: builder.mutation({ query: (data) => ({ url: '/history/new', method: 'POST', body: data, }), invalidatesTags: [{ type: 'Entry', id: 'LIST' }], }), updateEntry: builder.mutation({ query: (initialEntry) => ({ url: `/history/${initialEntry.Id}`, method: 'PUT', body: { ...initialEntry, date: new Date().toISOString(), }, }), invalidatesTags: (result, error, arg) => [{ type: 'Entry', id: arg.id }], }), deleteEntry: builder.mutation({ query: ({ id }) => ({ url: `/history/${id}`, method: 'DELETE', body: { id }, }), invalidatesTags: (result, error, arg) => [{ type: 'Entry', id: arg.id }], }), }), }) export const { useGetEntryQuery, useAddEntryMutation, useUpdateEntryMutation, useDeleteEntryMutation, } = entryApiSlice export const selectEntryResult = (state, params) => entryApiSlice.endpoints.getEntry.select(params)(state).data const entrySelectors = entryAdapter.getSelectors( (state) => selectEntryResult(state) ?? initialState ) export const selectEntry = entrySelectors.selectAll
Je l'utilise dans le composant Entries comme celui-ci
const { data: entriesData = [], refetch, isLoading, isSuccess, isError, error, } = useGetEntryQuery(filters) const entries = useSelector(selectEntry)
Remarque : si je supprime le "filtre" de la requête get, tout fonctionne comme avant (comme prévu, bien sûr).
Avertissement : je n'ai aucune idée de ce que je fais, j'ai lu la documentation et j'essaie de comprendre, donc tout commentaire est grandement apprécié. Merci!
P粉7795658552023-12-29 00:13:52
Oui, c'est un sujet un peu sensible, car la documentation de RTKQ a tendance à montrer les exemples les plus simples, c'est-à-dire des requêtes qui n'utilisent aucun paramètre. J'ai moi-même eu beaucoup de problèmes.
Quoi qu'il en soit, vous avez déclaré selectEntryResult
en fonction de deux paramètres : state et params. Ensuite, lorsque vous créez le sélecteur d'adaptateur en dessous, vous l'appelez avec un seul paramètre : state. De plus, lorsque vous utilisez le sélecteur final dans votre composant comme ceci :
const entries = useSelector(selectEntry);Les paramètres
sont introuvables, par défaut ils 未定义
et aucune donnée associée à ces paramètres de requête ne peut être trouvée.
L'élément clé à comprendre ici est que vous devez en fait transmettre les paramètres de requête à travers chaque niveau du sélecteur (chaque wrapper) d'une manière ou d'une autre.
Une façon ici est de "transférer" le paramètre via le sélecteur :
export const selectEntryResult = createSelector([state => state, (_, params) => params], (state, params) => entryApiSlice.endpoints.getEntry.select(params)(state)?.data ?? initialState)
Ici, nous utilisons la fonction createSelector
exportée depuis RTK. Ensuite, dans votre composant, vous feriez quelque chose comme ceci :
const {...} = useGetEntryQuery(filters); const entries = useSelector(state => selectEntry(state, filters));
Ceci est créé à l'aide de l'adaptateur d'entité selectAll
选择器时有效,但在使用 selectById
时会导致问题,因为该选择器也是参数化的。简而言之,selectById
Le sélecteur est défini en interne pour prendre un deuxième argument de l'identifiant d'entité que vous souhaitez récupérer, alors que la méthode que j'ai montrée utilise le deuxième argument pour transmettre les paramètres de requête (le filtre de votre appareil). cas).
Pour autant que je sache, il n'existe jusqu'à présent aucune solution qui fonctionne parfaitement et couvre tous les éléments suivants :
Une autre approche pourrait consister à créer des fabriques de sélecteurs qui créent dynamiquement des sélecteurs de base pour des combinaisons spécifiques de paramètres de requête.
J'ai déjà fabriqué un tel emballage qui peut être utilisé dans toutes les situations. Malheureusement, je ne peux pas le partager car il s'agit d'un package privé, mais l'idée de base est de modifier les paramètres pour que selectById
和 selectAll
(et tous les autres sélecteurs) fonctionnent correctement, en transmettant les paramètres de requête au sélecteur comme troisième argument, puis plus loin réemballer chaque sélecteur d'adaptateur d'entité :
export const createBaseSelector = (endpoint) => createSelector( [(state) => state, (_, other) => other, (_, _other, params) => params], (state, _other, params) => endpoint.select(params)(state) ); const selectors = adapter.getSelectors(baseSelector); // And then rewrap selectAll and selectById from 'selectors' above
Je sais que cela semble compliqué et je l'ai à peine fait fonctionner alors essayez d'éviter d'aller dans cette direction :)
Un article utile que j'ai trouvé en cours de route peut être trouvé ici, ils décrivent également quelques façons de créer des sélecteurs au niveau des composants et de les mémoriser, mais je ne les ai pas encore tous essayés. Jetez un œil, vous trouverez peut-être un moyen plus simple de résoudre votre problème spécifique.