我正在使用 Redux Toolkit 和 RTK 查詢 建立一個(gè)項(xiàng)目,並嘗試從 API 取得一些條目。我正在使用 createEntityAdapter 的規(guī)範(fàn)化資料方法,因?yàn)樵谀硞€(gè)元件中我需要將資料作為數(shù)組,所以我最終使用了選擇器?,F(xiàn)在我的問題是,由於我添加過濾器作為查詢的參數(shù),我的選擇器停止工作。
我在這裡研究了類似的問題,例如:“如何使用帶有參數(shù)的 RTK 查詢選擇器?”,但我太笨了,無法理解我應(yīng)該修改的內(nèi)容。我試圖理解 RTK 查詢文檔,但我做不到。
從上面的問題中,我知道我的選擇器還需要具有參數(shù),以便準(zhǔn)確地知道要選擇什麼,並且這不是推薦的模式,但我無法理解如何使其工作。
我的條目切片:
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
我在像這樣的 Entries 元件中使用它
const { data: entriesData = [], refetch, isLoading, isSuccess, isError, error, } = useGetEntryQuery(filters) const entries = useSelector(selectEntry)
注意:如果我從獲取查詢中刪除“過濾器”,一切都會(huì)像以前一樣工作(當(dāng)然,正如預(yù)期的那樣)。
免責(zé)聲明:我不知道我到底在做什麼,我已經(jīng)閱讀了文件並且正在嘗試弄清楚,所以我非常感謝任何反饋。 謝謝!
是的,這是一個(gè)有點(diǎn)敏感的話題,因?yàn)?RTKQ 的文件傾向於顯示最簡(jiǎn)單的範(fàn)例,即完全不使用任何參數(shù)的查詢。我自己也遇到過很多問題。
無論如何,您已將 selectEntryResult
宣告為兩個(gè)參數(shù)的函數(shù):state 和 params。然後,當(dāng)您在其下方建立適配器選擇器時(shí),您僅使用一個(gè)參數(shù)來呼叫它:狀態(tài)。此外,當(dāng)您在元件中使用最終選擇器時(shí),如下所示:
const entries = useSelector(selectEntry);
參數(shù)無處可尋,預(yù)設(shè)情況下它們未定義
,無法找到與此類查詢參數(shù)關(guān)聯(lián)的任何資料。
這裡要理解的關(guān)鍵是,您實(shí)際上需要以某種方式透過選擇器的每個(gè)層級(jí)(每個(gè)包裝器)傳遞查詢參數(shù)。
這裡的一種方法是透過選擇器「轉(zhuǎn)發(fā)」參數(shù):
export const selectEntryResult = createSelector([state => state, (_, params) => params], (state, params) => entryApiSlice.endpoints.getEntry.select(params)(state)?.data ?? initialState)
這裡我們使用從RTK匯出的createSelector
函數(shù)。然後在你的元件中你會(huì)做這樣的事情:
const {...} = useGetEntryQuery(filters); const entries = useSelector(state => selectEntry(state, filters));
這在使用實(shí)體適配器建立的 selectAll
選擇器時(shí)有效,但在使用 selectById
時(shí)會(huì)導(dǎo)致問題,因?yàn)樵撨x擇器也是參數(shù)化的。簡(jiǎn)而言之,selectById
選擇器在內(nèi)部定義為使用您希望檢索的實(shí)體id 的第二個(gè)參數(shù),而我展示的方法使用第二個(gè)參數(shù)來傳遞查詢參數(shù)(您的篩選器中的過濾器)。案例)。
據(jù)我所知,到目前為止還沒有解決方案可以完美運(yùn)行並涵蓋以下所有內(nèi)容:
另一種方法可能是建立一些選擇器工廠,這些選擇器工廠為查詢參數(shù)的特定組合動(dòng)態(tài)建立基本選擇器。
我曾經(jīng)製作過這樣一個(gè)包裝器,可以在所有情況下使用。不幸的是,我無法共享它,因?yàn)樗且粋€(gè)私有包,但基本思想是改變參數(shù),以便selectById
和selectAll
(以及所有其他選擇器)都可以正常工作,透過將查詢參數(shù)作為第三個(gè)參數(shù)傳遞給選擇器,然後進(jìn)一步重新包裝每個(gè)實(shí)體適配器選擇器:
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
我知道這聽起來很複雜,我?guī)缀鯖]有讓它工作,所以盡量避免朝這個(gè)方向走:)
可以找到我一路上找到的一篇有用的文章這裡,他們還描述了一些在組件級(jí)別創(chuàng)建選擇器並記住它們的方法,但我還沒有全部嘗試過??纯窗?,也許您會(huì)找到更簡(jiǎn)單的方法來解決您的特定問題。