首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RTK查询端点和RTK操作出现故障

RTK查询端点和RTK操作出现故障
EN

Stack Overflow用户
提问于 2022-07-21 21:12:32
回答 2查看 241关注 0票数 0

我遇到了一个奇怪的问题,我的RTK查询请求正在以一个奇怪的顺序发生。

我们得到了RTK sports切片,在同一个文件中我定义了useLoadSports钩子

代码语言:javascript
复制
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组件在加载整个应用程序所需的数据时使用这个钩子。

代码语言:javascript
复制
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

代码语言:javascript
复制
const PlayerPropsPage = () => {
  const { data, isLoading, isError, error } = useGetPropsDashboardQuery();
  useEffect(() => {
    console.log('LOADING PlayerPropsPage');
  }, [])
  
  return /* markup */
}

查询的queryFn使用useLoadSports保存到商店中的项目

代码语言:javascript
复制
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,但下面是日志:

代码语言:javascript
复制
useInitialLoad
useLoadSports
LOADING PlayerPropsPage
PROPS ENDPOINT
SETTING SPORTS

另一件疯狂的事情是,如果我将getState()调用移动到对baseQuery的调用之上的端点中,那么运动项目还没有被存储,并且会抛出错误。

为什么会这样?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-07-21 23:08:40

一堆随机观察:

  • 您真的不应该在这里将setSports操作分派到useEffect中。如果您真的想要一个带有useGetSportsQuery结果的片段,那么为api.endpoints.getSports.fulfilled添加一个extraReducers。请参阅这个例子
代码语言:javascript
复制
// 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()和所有其他魔术结合起来,这是永远不会发生的。
  • 您甚至可以进一步简化这一点:
代码语言:javascript
复制
const { data: sports } = useGetSportsQuery()
const result = useGetPropsDashboardQuery( sports ? sports : skipToken )

不需要切片,不需要将逻辑分散到多个组件上,也不需要queryFn。queryFn是一个逃生舱口,看起来你真的不需要它。

票数 1
EN

Stack Overflow用户

发布于 2022-07-21 21:52:15

目前的行为是正常的,即使这不是你所期望的。

  • 您有一个执行查询的主钩子
  • 第一个查询开始
  • 当查询完成时,它会执行"rerender“并执行以下操作
    • 传递运动的结果
    • 第二个查询开始

因此,当您开始第二个查询时,无法保证您在商店中有体育活动。一切都是用钩子做的(技术上可以用钩子来做,但这是另一个主题)

如何等待一个雷击的结果触发另一个?

你有多种方法可以做到。这也取决于您是否需要等待这两个查询。

侦听器中间件

如果您想在完成一次重击时运行一些逻辑,那么有一个侦听器可以帮助您。

代码语言:javascript
复制
listenerMiddleware.startListening({
  matcher: sportsApi.endpoints.getSports.fulfilled,
  effect: async (action, listenerApi) => {         
    listenerApi.dispatch(dashboardApi.endpoints.getPropsDashboard.initiate())
   }
  },
})

此外,不要在商店中设置带有dispatchuseEffect中的运动。您可以将查询插入extraReducers。以下是一个例子:

代码语言:javascript
复制
createSlice({
  name: 'sports',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addMatcher(
        sportsApi.endpoints.getSports.fulfilled,
        (state, action) => {
          state.sports = action.payload.sports
        }
      )
  },
})

用选择器注入thunk参数

如果您将体育作为变量直接传递给查询时,它们将重新触发查询。以下是一个例子:

代码语言:javascript
复制
const PlayerPropsPage = () => {
  const { data: sports, ...result } = useGetSportsQuery();
  const { data, isLoading, isError, error } = useGetPropsDashboardQuery(sports);
}

在单个queryFn中执行两个查询

如果在单个queryFn中,您可以通过等待它们来链接这些查询

代码语言:javascript
复制
 queryFn: async (_args, { getState }, _extraOptions, baseQuery) => {
        const resultFirstQuery = await baseQuery({ url: firstQueryUrl });
        const resultSecondQuery = await baseQuery({ url: secondQueryUrl });
        // Do stuff
      },

注意:

  • 当您在thunk中使用getState()时,如果商店更新,这将不会“自动”触发您的thunk。
  • 我不知道您是否需要这项运动来执行第二个查询或将两个查询的结果组合在一起。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73072685

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档