【问题标题】:Error: Invalid hook call. Hooks can only be called inside of the body of a function component - When adding Loader component错误:无效的挂钩调用。 Hooks 只能在函数组件的主体内部调用 - 添加 Loader 组件时
【发布时间】:2021-11-22 08:04:45
【问题描述】:

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

这是我的代码:

LoderContext.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;

Loder.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 只能在函数组件内部调用

我的代码有什么错误?

【问题讨论】:

  • 嗯,您目前在函数组件的主体之外使用了多个钩子。 useRouter, useLoading, useEffect

标签: reactjs react-hooks next.js


【解决方案1】:

您的索引页面在Home 组件之外调用useLoadinguseEffectuseRouter

参考反应documentation。它清楚地提到了您面临的问题。

钩子只能在函数组件内部调用。

应该是这样的。

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>
        </>
      )}
    </>
  );
};

【讨论】:

  • 谢谢。但是我又得到了Server Error Error: useCount must be used within a CountProvider这个错误。你知道为什么吗?
  • 您只能在提供程序中使用上下文。因此,您使用 useCount 的组件应该是该上下文中 Provider 的子级。
猜你喜欢
  • 2020-07-22
  • 2020-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-01
  • 1970-01-01
  • 2021-10-25
相关资源
最近更新 更多