无效的挂钩调用。钩子只能在反应函数组件内部使用...... useEffect,redux

Posted

技术标签:

【中文标题】无效的挂钩调用。钩子只能在反应函数组件内部使用...... useEffect,redux【英文标题】:Invalid hook call. Hooks can only be used inside of a react function component... useEffect, redux 【发布时间】:2021-12-26 13:30:43 【问题描述】:

我的 react 应用程序遇到了与钩子相关的问题。使用的技术:React、Redux、Apollo、ChakraUI。

这是困扰我的 React 组件:

import React,  useEffect  from "react";
import  Flex, Container, Heading, Text  from "@chakra-ui/react";
import  connect, useSelector, useDispatch  from "react-redux";
import  State  from "../state/store";
import  fetchRecipes  from "../state/recipe/actions";

interface RecipesListProps 

const RecipesList: React.FC<RecipesListProps> = () => 

  const recipes = useSelector<State>(
    (state) => state.recipe.recipes
  ) as State["recipe"]["recipes"];

  const loading = useSelector<State>(
    (state) => state.recipe.loading
  ) as State["recipe"]["loading"];

  const dispatch = useDispatch();

  useEffect(() => 
    dispatch(fetchRecipes());
  , []);

  if (loading) 
    return <h1>Loading....</h1>;
  
  return (
    <Flex
      m="auto"
      mt="5rem"
      w="50%"
      direction="column"
      justifyContent="center"
      alignItems="center"
    >
      <Heading>Your Recipes</Heading>
      <Flex mt="2rem" direction="column" w="100%" padding="0" gridGap="2rem">
        recipes &&
          recipes.map((recipe) => (
            <Container
              key=recipe.id
              bg="orange.100"
              borderRadius="0.2rem"
              padding="1rem"
              maxW="100%"
            >
              <Text fontSize="xl" fontWeight="bold">
                recipe.title
              </Text>
              <Text>recipe.description</Text>
            </Container>
          ))
      </Flex>
    </Flex>
  );
;

export default RecipesList;

注意useEffect() 钩子的使用。这是我得到的错误:


Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app

我很确定我违反了规则编号 2,即我违反了 Hooks 规则。一旦我从组件中取出useEffect() 调用,它就不会引发错误。

有人可以就我做错了什么提供一些指导吗? 谢谢。

编辑:

fetchRecipes 函数是一个 Redux thunk 函数,它从 graphql 服务器获取食谱

更新:

我一直在想办法解决这个问题。我用console.log("hello world") 替换了dispatch(fetchRecipes()) 调用,效果很好!

这让我大吃一惊!这是fetchRecipes 函数的问题吗?

编辑:

这是fetchRecipes 函数的代码:

export const fetchRecipes = () => 
  return (dispatch: Dispatch) => 
    dispatch(fetchRecipesPending());
    const  data  = useRecipesQuery();
    const errors = data?.recipes.errors;
    const recipes = data?.recipes.recipes;
    if (errors?.length) 
      dispatch(fetchRecipesFailure(errors));
     else 
      dispatch(fetchRecipesSuccess(recipes));
    
  ;
;

useRecipesQuery 是使用graphql-codegen 库自动生成的自定义挂钩。它建立在 @apollo/client 库中的 useQuery 钩子之上。

【问题讨论】:

fetchRecipes 是做什么的? 我添加了fetchRecipes函数的小描述。如果您需要了解更多信息,请告诉我...非常感谢! 顺便说一下,我没有在这个项目中使用 Redux Toolkit,只是让你知道 请分享fetchRecipes的实际代码。我打赌你在那里使用了一个钩子,因此违反了钩子的规则。题外话,你真的应该使用 Redux Toolkit。多年来,它是每个 Redux 代码的官方推荐。 其实我在fetchRecipes中使用了一个钩子!我会马上分享它的代码! 【参考方案1】:

您的useEffect 需要稍作改写。您正在调度函数fetchRecipes,它本身就是一个钩子,但调度的东西应该是一个简单的“动作”(在此处使用 Redux 术语)。所以我想我们可以通过分解你的 fetchRecipes fn 来解决这个问题。

组件的 sn-p 现在如下所示:

const  data  = useRecipesQuery();

useEffect(() => 
  if (!data) 
    dispatch(fetchRecipesPending()) // I only assume you fetch on render
  
  if (data?.recipes?.errors) 
    dispatch(fetchRecipesFailure(data?.recipes.errors)
  
  if (data?.recipes?.recipes) 
    dispatch(fetchRecipesSuccess(data?.recipes?.recipes)))
  
, [data]);

现在它应该没问题并且更具可读性。无论哪种方式,正如一些人已经建议的那样,我会考虑使用一些更标准化的方式,比如使用带有 Thunks 或 Sagas 的 Redux,或者,甚至更好——我看到你可能正在做一个 GQL 查询——如果是这样,只需使用一个钩子它并使用 Apollo Client 处理数据。

【讨论】:

以上是关于无效的挂钩调用。钩子只能在反应函数组件内部使用...... useEffect,redux的主要内容,如果未能解决你的问题,请参考以下文章

错误:无效的挂钩调用。钩子只能在函数组件的主体内部调用。 【我还在用函数组件】

× 错误:无效的挂钩调用。 Hooks 只能在函数组件的主体内部调用。[ReactJS]

错误:无效的挂钩调用。钩子只能在函数组件的主体内部调用。 (React-hooks React-native)

反应:无效的钩子调用。 Hooks 只能在函数组件的主体内部调用

无效的钩子调用错误:只能在函数组件的主体内部调用钩子

“无效的钩子调用。只能在函数组件的主体内部调用钩子”问题