首页 > 解决方案 > 错误:无效的挂钩调用。Hooks 只能在函数组件的主体内部调用 - 添加 Loader 组件时

问题描述

我正在做一个 Nextjs - Typescript 项目。我正在尝试添加一个 Loader 组件。页面正在加载加载器组件时为真。否则为假。

这是我的代码:

加载上下文.ts

import React, { useReducer } from "react";
import { NextPage } from "next";
type State = { loading: boolean };
type Action = { type: "startLoading" } | { type: "endLoading" };
type Dispatch = (action: Action) => void;

export const LoadingContext =
  React.createContext<{ state: State; dispatch: Dispatch } | undefined>(
    undefined
  );

const initialState = {
  loading: true,
};

const { Provider } = LoadingContext;

const reducer = (state: State, action: Action) => {
  switch (action.type) {
    case "startLoading":
      return {
        loading: true,
      };
    case "endLoading":
      return {
        loading: false,
      };
    default:
      throw state;
  }
};

const LoadingProvider: NextPage = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const value = { state, dispatch };
  return <Provider value={value}>{children}</Provider>;
};

export function useLoading() {
  const context = React.useContext(LoadingContext);         // error is somewhere here
  if (context === undefined) {
    throw new Error("useCount must be used within a CountProvider");
  }
  return context;
}

export default LoadingProvider;

加载器.tsx

const Loader: NextPage = () => {
  return (
    <div className={styles.loader_wrapper}>
      <div className={styles.content}>
        <span className={styles.loading_text}>Loading...</span>
      </div>
    </div>
  );
};

export default Loader;

索引.tsx

import Loader from "../components/Loader/Loader";
import { useLoading } from "../context/LoadingContext";
import { useRouter } from "next/dist/client/router";

const { state, dispatch } = useLoading();

const router = useRouter();

useEffect(() => {
  router.events.on("routeChangeStart", () => {
    dispatch({ type: "startLoading" });
  });

  return () => {
    router.events.off("routeChangeStart", () => {
      dispatch({ type: "endLoading" });
    });
  };
}, [dispatch, router]);

useEffect(() => {
  dispatch({ type: "endLoading" });
}, [dispatch, router]);

const Home: NextPage = () => {
  return (
    <>
      {state.loading ? (
        <Loader />
      ) : (
        <>
          <div>
           // other components
          </div>
        </>
      )}
    </>
  );
};

我得到了这个错误。错误:无效的挂钩调用。Hooks 只能在函数组件的主体内部调用

我的代码中有哪些错误?

标签: reactjsreact-hooksnext.js

解决方案


您的索引页面正在调用useLoadinguseEffect并且useRouterHome组件之外。

请参阅反应文档。它清楚地提到了您面临的问题。

Hooks 只能在函数组件的主体内部调用。

它应该是这样的。

import Loader from "../components/Loader/Loader";
import { useLoading } from "../context/LoadingContext";
import { useRouter } from "next/dist/client/router";

const Home: NextPage = () => {

  const { state, dispatch } = useLoading();

  const router = useRouter();

  useEffect(() => {
    router.events.on("routeChangeStart", () => {
      dispatch({ type: "startLoading" });
    });

    return () => {
      router.events.off("routeChangeStart", () => {
        dispatch({ type: "endLoading" });
      });
    };
  }, [dispatch, router]);

  useEffect(() => {
    dispatch({ type: "endLoading" });
  }, [dispatch, router]);

  return (
    <>
      {state.loading ? (
        <Loader />
      ) : (
        <>
          <div>
           // other components
          </div>
        </>
      )}
    </>
  );
};


推荐阅读