我是Redux RTK的新手,所以问题可能不完全是在调用getSelectors()上。然而,当我使用来自getSelectors()的状态时,它会重新加载整个状态。
基线是基于documentId调用不同的Setup对象。这些Setup对象非常大,所以在getsetup中我只获取一些基本属性。然后,当用户从下拉菜单中选择特定的设置时,我想将其保存在setupSlice中。但是当我触发调度(setSetup(data))时,RTK重新加载所有的设置。我遇到了一个无限循环,当获取所有的Setup对象后,我想自动分配默认的Setup给setupSlice。
额外理想情况下,当我给setupSlice分配一个Setup时,我想从RTK调用getSetup来获取该特定Setup的整个Setup对象并将其存储在setupSlice中。
我不确定这是否应该发生,但无论如何要阻止它?除此之外,你有什么建议让我继续吗?
这是我要生成的组件:
const SetupDropdown = () => {
const dispatch = useDispatch()
const { documentId } = useParams()
const { data, isFetching } = useGetSetupsQuery({ documentId })
let setupsMenu;
const { selectAll: selectAllSetups } = getSelectors({documentId})
const allSetups = useSelector(selectAllSetups)
if (!isFetching) {
const defaultSetup = allSetups.find((setup) => setup.default)
setupsMenu = allSetups.map(setup => {
return (<MenuItem value={setup.id}>{setup.name}</MenuItem>)
})
dispatch(setSetup(defaultSetup))
}
const setupId = useSelector(selectSetupId)
const handleChange = async (event) => {
// Here I ideally call the getSetup RTK Query to fetch the entire information of the single setup
const data = {
id: event.target.value,
name: 'Random name'
}
dispatch(setSetup(data))
};
return (
<FormControl sx={{ minWidth: 200 }} size="small">
<InputLabel>Setup</InputLabel>
<Select
value={setupId}
onChange={handleChange}
label="Setup"
>
{setupsMenu}
</Select>
</FormControl>
)
}
export default SetupDropdown;
这是setupapisice:
const setupsAdapter = createEntityAdapter({
sortComparer: (a, b) => b.date.localeCompare(a.date)
})
const initialState = setupsAdapter.getInitialState()
export const setupsApiSlice = apiSlice.injectEndpoints({
tagTypes: ['Setup'],
endpoints: builder => ({
getSetups: builder.query({
query: ({ documentId }) => ({
url: `/documents/${documentId}/setups`,
method: 'GET'
}),
transformResponse: responseData => {
return setupsAdapter.setAll(initialState, responseData)
},
providesTags: (result, error, arg) => [
{ type: 'Setup', id: "LIST" },
...result.ids.map(id => ({ type: 'Setup', id }))
]
}),
getSetup: builder.query({
query: ({ documentId, setupId }) => ({
url: `/documents/${documentId}/setups/${setupId}`,
method: 'GET'
})
})
})
})
export const {
useGetSetupsQuery,
useGetSetupQuery
} = setupsApiSlice
// Define function to get selectors based on arguments (query) of getSetups
export const getSelectors = (
query,
) => {
const selectSetupsResult = setupsApiSlice.endpoints.getSetups.select(query)
const adapterSelectors = createSelector(
selectSetupsResult,
(result) => setupsAdapter.getSelectors(() => result?.data ?? initialState)
)
return {
selectAll: createSelector(adapterSelectors, (s) =>
s.selectAll(undefined)
),
selectEntities: createSelector(adapterSelectors, (s) =>
s.selectEntities(undefined)
),
selectIds: createSelector(adapterSelectors, (s) =>
s.selectIds(undefined)
),
selectTotal: createSelector(adapterSelectors, (s) =>
s.selectTotal(undefined)
),
selectById: (id) => createSelector(adapterSelectors, (s) =>
s.selectById(s, id)
),
}
}
这是setupSplice:
const initialState = {
name: null,
filters: [],
data: {},
status: 'idle', //'idle' | 'loading' | 'succeeded' | 'failed'
error: null
}
const setupSlice = createSlice({
name: 'setup',
initialState,
reducers: {
setSetup: (state, action) => {
console.log('Dispatch')
const setup = action.payload;
console.log(setup)
state.id = setup.id;
state.name = setup.name;
state.filters = setup.filters;
state.data = setup.state;
state.status = 'succeeded';
}
}
})
export const { setSetup } = setupSlice.actions;
export const selectSetupId = (state) => state.setup.id;
export const selectSetupName = (state) => state.setup.name;
export const selectSetupFilters = (state) => state.setup.filters;
export const selectSetupData = (state) => state.setup.data;
export default setupSlice.reducer;
,你可能应该在你的useGetSetupsQuery
中使用selectFromResult
,而不是添加另一个useSelector
钩子。这也将大大降低代码的复杂性。
你的问题是,你是在你的组件中创建这些选择器在每次渲染-所以他们没有机会真正记住并给你一个稳定的结果。如果您在组件中这样做,请将其封装在useMemo
调用中,以保持选择器实例尽可能稳定。