简体   繁体   English

如何在 react useCallback 中调用 react hook

[英]How to call react hook inside of a react useCallback

I have a next.js react application.我有一个 next.js 反应应用程序。

There is a portion of my app which is called "Banners" i am building a "store" using the Context API. However when i call the "useFetchBanners" function within my page i get the following error.我的应用程序中有一部分称为“横幅”,我正在使用上下文 API 构建“商店”。但是,当我在页面中调用“useFetchBanners”function 时,出现以下错误。 This function is used to set the initial state of the page.这个function用来设置页面的初始state。

  1. React Hook "useFetchBanners" cannot be called inside a callback.无法在回调内调用 React Hook“useFetchBanners”。 React Hooks must be called in a React function component or a custom React Hook function. [Error/react-hooks/rules-of-hooks] React Hooks 必须在 React function 组件或自定义 React Hook function 中调用。[Error/react-hooks/rules-of-hooks]

BannersStore.tsx横幅商店.tsx

import { createContext, useCallback, useContext, useState } from "react";
import { AppContext } from "src/contexts/app/AppContext";
import { GetBanners, IGetBannersQuery, IGetBannersResponse } from "src/services/BannersService.";

interface IBannerStore {
    isLoading: boolean;
}

const useStore = () => {
    const appContext = useContext(AppContext);
    const [isLoading, setIsLoading] = useState<boolean>(false);
    const [data, setData] = useState<IGetBannersResponse | null>(null);
    const [error, setError] = useState<any>(null);
    const [searchQuery, setSearchQuery] = useState<IGetBannersQuery>({});

    const fetchBanners = async (params: IGetBannersQuery) => {
        const [results, error] = await GetBanners(params, appContext.token);
        if (results.status !== 200 || error) {
            setError(error);
        }
        setData(results.data || null);
    };

    return {
        isLoading,
        setIsLoading,
        data,
        setData,
        searchQuery,
        setSearchQuery,
        fetchBanners: (params: IGetBannersQuery) => fetchBanners(params),
    };
};

const StoreContext = createContext<any>(null);

export const StoreContextProvider = ({ children }: any) => <StoreContext.Provider value={useStore()}>{children}</StoreContext.Provider>;

export const useIsLoading = () => useContext(StoreContext).isLoading;
export const useSetIsLoading = () => useContext(StoreContext).setIsLoading;
export const useData = () => useContext(StoreContext).data;
export const useSetData = () => useContext(StoreContext).setData;
export const useSearchQuery = () => useContext(StoreContext).searchQuery;
export const useSetSearchQuery = () => useContext(StoreContext).setSearchQuery;
export const useFetchBanners = (params: IGetBannersQuery) => useContext(StoreContext).fetchBanners;

I want to call the function useFetchBanners to set the initial data when the page loads.我想在页面加载时调用 function useFetchBanners来设置初始数据。 (taking into account the existing browser params that might exist) (考虑到可能存在的现有浏览器参数)

BannersPage.tsx横幅页面.tsx

...
   const init = useCallback(async () => {
        if (router.isReady === false) {
            return;
        }
        let loadBrowserSearchParams = null;
        if (!_.isEmpty(router.query)) {
            loadBrowserSearchParams = {
               ...
             }
        }

        // error here
        useFetchBanners(loadBrowserSearchParams);

    }, [router]);

    useEffect(() => {
        init();
    }, [init, router]);

...

It seems like i can't call my useFetchBanners inside of the useCallback.似乎我无法在 useCallback 中调用我的 useFetchBanners。

I think your hook is already written correctly, you just need to use it differently.我认为您的钩子已经正确编写,您只需要以不同的方式使用它。 Call it in the body of your component, and it returns a function to you, and then you can call that function later.在您的组件主体中调用它,它会返回一个 function 给您,然后您可以稍后调用该 function。

// bannersPage.tsx
const fetchBanners = useFetchBanners();

const init = useCallback(async () => {
  if (router.isReady === false) {
    return;
  }
  let loadBrowserSearchParams = null;
  if (!_.isEmpty(router.query)) {
    loadBrowserSearchParams = {
       ...
    };
  }

  fetchBanners(loadBrowserSearchParams);
}, [router]);

useEffect(() => {
  init();
}, [init, router]);

PS, if the init function is only needed in the effect, you can move it inside the effect: PS,如果效果中只需要init function,可以移到效果里面:

const fetchBanners = useFetchBanners();
useEffect(() => {
  if (router.isReady === false) {
    return;
  }
  let loadBrowserSearchParams = null;
  if (!_.isEmpty(router.query)) {
    loadBrowserSearchParams = {
       ...
    };
  }

  fetchBanners(loadBrowserSearchParams);
}, [router]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM