【问题标题】:Redux RTK reloading state when calling getSelectors调用 getSelectors 时 Redux RTK 重载状态
【发布时间】:2022-06-10 23:29:12
【问题描述】:

我是 Redux RTK 的新手,所以问题可能并不完全在于调用 getSelectors()。但是,当我使用来自 getSelectors() 的状态时,它会重新加载整个状态。

问题 基线是我根据 documentId 调用不同的 Setup 对象。这些设置对象非常大,所以在 getSetups 中我只获取一些基本属性。然后,当用户从下拉列表中选择特定设置时,我想将其保存在 setupSlice 中。但是当我触发 dispatch(setSetup(data)) 时,RTK 会重新加载所有设置。 获取所有设置对象后,我遇到了一个无限循环,我想自动将默认设置分配给 setupSlice。

额外 理想情况下,当我将 Setup 分配给 setupSlice 时,我想从 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;

这是 setupApiSlice:

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;

【问题讨论】:

    标签: react-redux redux-toolkit rtk-query


    【解决方案1】:

    Tbh.,您可能应该在您的 useGetSetupsQuery 中使用 selectFromResult 而不是添加另一个 useSelector 挂钩。这也将大大降低您的代码复杂性。

    您的问题是您在每次渲染时在组件内创建这些选择器 - 因此它们没有机会实际记忆并为您提供稳定的结果。如果您在组件中执行此操作,请将其包装在 useMemo 调用中,以使您的选择器实例尽可能稳定。

    【讨论】:

      猜你喜欢
      • 2021-02-06
      • 2022-08-06
      • 1970-01-01
      • 2021-12-08
      • 2019-09-24
      • 2019-06-09
      • 1970-01-01
      • 2018-06-07
      • 2022-08-03
      相关资源
      最近更新 更多