javascript 无法在函数内部使用我的React自定义挂钩,给予错误

qfe3c7zg  于 2022-12-10  发布在  Java
关注(0)|答案(2)|浏览(150)

我建立了一个简单的项目来提高我在react框架中的技能,我的项目,它从API中获取一些数据,称为Bored API,它提供了一些不同类别的活动,如烹饪或DIY等,并使用翻译器API将活动翻译为阿拉伯语。我的问题是我做了两个hooks,第一个是useBored,它获取该活动并将其发送到称为useTranslate的第二个hook,该useTranslate将文本发送到翻译器API以便更好地理解,以下是代码:
App.tsx

import React, { useEffect, useState } from "react";
import CardComp from "./components/CardComp";
import images no need to copy it here
const App: React.FC = () => {
  const [final, setfinalD] = useState<string>(""); //this state used after I get the final text from translator 
  useEffect(() => {
    console.log(final); 
  }, [final]);

  return (
    <div className=" bg-gradient-to-bl from-gray-700 via-gray-900 to-black flex justify-center items-center h-[100vh] w-[100vw]">
      <div className="grid gap-2 grid-cols-2 grid-rows-3 ">
        <CardComp
          placeholder="تــعـلـوم"
          image={education}
          setD={setfinalD}
          type={"education"}
        />
        <CardComp
          placeholder="نـشـاطـات"
          image={kite}
          setD={setfinalD}
          type={"recreational"}
        />
        <CardComp
          placeholder="أجتـماعـيات"
          image={social}
          setD={setfinalD}
          type={"social"}
        />
        <CardComp
          placeholder="أفعلها بـنـفسك"
          image={diy}
          setD={setfinalD}
          type={"diy"}
        />
        <CardComp
          placeholder="عمل خــيـر"
          image={social}
          setD={setfinalD}
          type={"charity"}
        />
        <CardComp
          placeholder="طـبخ"
          image={cooking}
          setD={setfinalD}
          type={"cooking"}
        />
        <CardComp
          placeholder="أسـترخاء"
          image={education}
          setD={setfinalD}
          type={"relaxation"}
        />
        <CardComp
          placeholder="عــمــل"
          image={work}
          setD={setfinalD}
          type={"busywork"}
        />
      </div>
      {final ? <p>{final}</p> : null} // here print the translated text
    </div>
  );
};

export default App;

现在CardComp.tsx

import React from "react";
import { useBored } from "../hooks/useBored";
import { useTranslate } from "../hooks/useTranslate";

interface ICard {
  placeholder: string;
  image: string;
  type: string;
  setD: React.Dispatch<React.SetStateAction<string>>; 
}

const CardComp: React.FC<ICard> = ({ placeholder, image, type, setD }) => {
  const getTheData = () => { // *ERROR* came from here
    const { data: dd } = useBored(type);
    const { data, isLoading, error } = useTranslate(dd[0]);
    if (isLoading === false) {
      setD(data);
    }
  };
  return (
    <div>
      <div
        onClick={getTheData}
        className="flex flex-col justify-center items-center p-7 cursor-pointer  font-mono bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-blue-700 via-blue-800 to-gray-900"
      >
        <div className=" ">
          <img src={image} className="w-[2.3em]" />
        </div>
        <h3>{placeholder}</h3>
      </div>
    </div>
  );
};

export default CardComp;

现在useBored.ts

import { useState, useEffect } from "react";

export const useBored = (type: string) => {
  const [data, setData] = useState<string[]>([]);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [error, setError] = useState<string>("");

  useEffect(() => {
    fetch(`http://www.boredapi.com/api/activity?type=${type}`)
      .then((r) => r.json())
      .then((r) => (setIsLoading(false), setData([r.activity, r.link])))
      .catch((e) => setError(e));
  }, [type]);
  console.log(data);
  return { data };
};

最后一个钩子是useTranslate.ts

import { useState, useEffect } from "react";

export const useTranslate = (text: string) => {
  const [data, setData] = useState<null | string>(null);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [error, setError] = useState<string>("");

  useEffect(() => {
    fetch(`https://api.mymemory.translated.net/get?q=${text}&langpair=en|ar`)
      .then((r) => r.json())
      .then((r) => (setIsLoading(false), setData(r.matches[0].translation)))
      .catch((e) => setError(e));
  }, [text]);
  return { data, isLoading, error };
};

如您所见,这是我的项目,错误来自CardComp中的getTheData函数,如果在函数之外使用hooks,它会工作,但不是我想要的,* 错误 * 是:

请告诉我出了什么事,谢谢。
我用顺风做造型。

nnsrf1az

nnsrf1az1#

不能从未将自身标识为react组件的函数调用任何钩子。由于您是新手,因此为了给予您一些知识,函数被标识为react函数组件,如下所示:

  • 函数应以大写字母开头(例如:组件和非组件)
  • 可以或不能返回某些JSX,但如果没有返回JSX,则应返回null

随后,您还应该从react类组件的render函数或从另一个函数组件返回组件,而不是像常规函数那样调用它(例如:组件()将引发错误.是使用react组件得正确方法).
现在,我们已经清楚了react组件是什么样子的,从这里你应该很清楚你的问题是什么。
你正在示例化你的钩子useBored

const getTheData = () => {
    const { data: dd } = useBored(type);
    const { data, isLoading, error } = useTranslate(dd[0]);
    if (isLoading === false) {
      setD(data);
    }
};

你不能在getTheData函数中示例化你的钩子,因为它没有把自己标识为一个react组件(参考上面的要点)。
因此,要解决这个问题,必须在getTheData函数之外示例化钩子。
我想你可以修改你的代码库来遵循这一点。希望它有帮助。

wydwbb8l

wydwbb8l2#

在出现错误的CardComp组件getTheData函数中,文档显示不允许这样做(在一个函数中调用一个hook,该函数是一个onclick处理程序)。因此,您不能这样做。控制台错误中的链接显示,只能调用hook:
1.在函数组件主体的顶层
1.在自定义挂钩的顶级正文中
文档中还提到,您可以安装eslint-plugin-react-hooks插件来捕获这些错误
但这是有意义的--这些自定义钩子也调用useState和useEffect。它们是为了与组件的生命周期一起工作。在onClick处理程序中调用这些钩子是没有意义的,因为这超出了组件的生命周期,并由用户交互启动。useEffect在每次更新时运行,并可以选择在组件卸载时返回一个cleanup回调。在您的情况下,在单击按钮之前,不会在自定义钩子内调用useEffect,这会破坏预期的范例。
从你的两个钩子看,我觉得你是在一个onClick处理程序中获取数据。useEffect通常用于加载组件的初始数据,但不是在处理程序中。
我们将Redux与React结合使用,这样我们就可以调度一个动作来调用fetch,并让该动作调度一个带有fetch响应有效载荷的“response”动作,然后Reducer可以更新状态,CardComp将适当地重新渲染。

相关问题