我遇到了一个奇怪的问题,我的RTK查询请求正在以一个奇怪的顺序发生。
我们得到了RTK sports切片,在同一个文件中我定义了useLoadSports钩子
const sportsSlice = createSlice({
name: 'sports', initialState: {},
reducers: {
setSports: (state, action) => action.payload,
},
});
export const sports = sportsSlice.reducer;
export const { setSports } = sportsSlice.actions;
export const useLoadSports = () => {
const dispatch = useDispatch();
const { data: sports, ...result } = useGetSportsQuery();
useEffect(() => { console.log('useLoadSports'); }, []);
useEffect(() => {
if (sports) {
console.log('SETTING SPORTS');
dispatch(setSports(sports));
}
}, [sports]);
return result;
};Application组件在加载整个应用程序所需的数据时使用这个钩子。
const useInitialLoad = () => {
useEffect(() => {
console.log('useInitialLoad');
}, []);
const { isLoading: sportsLoading } = useLoadSports(); // below
const ready = !sportsLoading;
return { ready };
};
const Application: React.FC<Props> = () => {
const { ready } = useInitialLoad();
if (!ready) return <h1>Loading app data</h1>;
return (
<S.Wrapper>
<AppRouter />
</S.Wrapper>
);
};实际上,AppRouter迭代一个配置对象来创建Route,我假设这不是我们的问题。
无论如何,PlayerPropsPage组件调用useGetPropsDashboardQuery。
const PlayerPropsPage = () => {
const { data, isLoading, isError, error } = useGetPropsDashboardQuery();
useEffect(() => {
console.log('LOADING PlayerPropsPage');
}, [])
return /* markup */
}查询的queryFn使用useLoadSports保存到商店中的项目
export const { useGetPropsDashboardQuery, ...extendedApi } = adminApi.injectEndpoints({
endpoints: build => ({
getPropsDashboard: build.query<PropAdminUIDashBoard, void>({
queryFn: async (_args, { getState }, _extraOptions, baseQuery) => {
console.log('PROPS ENDPOINT');
const result = await baseQuery({ url });
const dashboard = result.data as PropAdminDashBoard;
const { sports } = getState() as RootState;
if (!Object.entries(sports).length) {
throw new Error('No sports found');
}
// use the sports, etc.
},
}),
}),
});我认为它会在呈现路由器之前使用setSports操作(因此调用道具端点或加载页面,我真的认为它会在调用道具查询之前呈现PlayerPropsPage,但下面是日志:
useInitialLoad
useLoadSports
LOADING PlayerPropsPage
PROPS ENDPOINT
SETTING SPORTS另一件疯狂的事情是,如果我将getState()调用移动到对baseQuery的调用之上的端点中,那么运动项目还没有被存储,并且会抛出错误。
为什么会这样?
发布于 2022-07-21 23:08:40
一堆随机观察:
setSports操作分派到useEffect中。如果您真的想要一个带有useGetSportsQuery结果的片段,那么为api.endpoints.getSports.fulfilled添加一个extraReducers。请参阅这个例子// from the example
extraReducers: (builder) => {
builder.addMatcher(
api.endpoints.login.matchFulfilled,
(state, { payload }) => {
state.token = payload.token
state.user = payload.user
}
)
},queryFn而将数据复制到状态中,而不是仅仅将其作为道具传递,使用query并以useGetPropsDashboardQuery(sports)的形式传入。这样,如果getPropsDashboard参数发生变化,那么sports就会更新--如果您将额外的逻辑与getState()和所有其他魔术结合起来,这是永远不会发生的。const { data: sports } = useGetSportsQuery()
const result = useGetPropsDashboardQuery( sports ? sports : skipToken )不需要切片,不需要将逻辑分散到多个组件上,也不需要queryFn。queryFn是一个逃生舱口,看起来你真的不需要它。
发布于 2022-07-21 21:52:15
目前的行为是正常的,即使这不是你所期望的。
因此,当您开始第二个查询时,无法保证您在商店中有体育活动。一切都是用钩子做的(技术上可以用钩子来做,但这是另一个主题)
如何等待一个雷击的结果触发另一个?
你有多种方法可以做到。这也取决于您是否需要等待这两个查询。
如果您想在完成一次重击时运行一些逻辑,那么有一个侦听器可以帮助您。
listenerMiddleware.startListening({
matcher: sportsApi.endpoints.getSports.fulfilled,
effect: async (action, listenerApi) => {
listenerApi.dispatch(dashboardApi.endpoints.getPropsDashboard.initiate())
}
},
})此外,不要在商店中设置带有dispatch的useEffect中的运动。您可以将查询插入extraReducers。以下是一个例子:
createSlice({
name: 'sports',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addMatcher(
sportsApi.endpoints.getSports.fulfilled,
(state, action) => {
state.sports = action.payload.sports
}
)
},
})用选择器注入thunk参数
如果您将体育作为变量直接传递给查询时,它们将重新触发查询。以下是一个例子:
const PlayerPropsPage = () => {
const { data: sports, ...result } = useGetSportsQuery();
const { data, isLoading, isError, error } = useGetPropsDashboardQuery(sports);
}在单个queryFn中执行两个查询
如果在单个queryFn中,您可以通过等待它们来链接这些查询
queryFn: async (_args, { getState }, _extraOptions, baseQuery) => {
const resultFirstQuery = await baseQuery({ url: firstQueryUrl });
const resultSecondQuery = await baseQuery({ url: secondQueryUrl });
// Do stuff
},注意:
getState()时,如果商店更新,这将不会“自动”触发您的thunk。https://stackoverflow.com/questions/73072685
复制相似问题