如何在另一个自定义Hook中使用一个返回值的自定义Hook?

回答 2 浏览 5775 2021-12-29

我正在使用React-native,在其中,我有一个名为useUser的自定义Hook,它使用Auth.getUserInfro方法从AWS Amplify获取用户信息,然后获取返回对象的一部分并将其设置为一个状态变量。我还有一个叫做useData的Hook,它根据userId来获取一些数据,并将其设置为一个状态变量。

useUser自定义钩子:

import React, { useState, useEffect } from "react";
import { Auth } from "aws-amplify";

const getUserInfo = async () => {
  try {
    const userInfo = await Auth.currentUserInfo();
    const userId = userInfo?.attributes?.sub;
    return userId;
  } catch (e) {
    console.log("Failed to get the  AuthUserId", e);
  }
};

const useUserId = () => {
  const [id, setId] = useState("");

  useEffect(() => {
    getUserInfo().then((userId) => {
      setId(userId);
    });
  }, []);

  return id;
};

export default useUserId;
import useUserId from "./UseUserId";
// ...rest of the necessary imports

const fetchData = async (userId) = > { // code to fetch data from GraphQl}

const useData = () => {
    const [data, setData] = useState();
    
    useEffect(() => { 
        const userId = useUser();
        fetchData(userId).then( // the rest of the code to set the state variable data.)
    },[])

    return data
   }

当我试图这样做的时候,我得到一个错误,告诉我

*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 See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.*

我认为问题在于我在使用效果里面调用了Hook useUser,但是在函数里面使用它将导致这里描述的问题,而且我不能在fetchData的主体之外使用它,因为useData本身是一个钩子,它只能在一个功能组件或Hook的主体里面使用。所以我不知道如何找到一个解决这个问题的方法。

Ramin Zandvakili 提问于2021-12-29
为什么你坚持要把简单的获取包在一个钩子里呢? 只要在useData钩子里调用getUserInfo就可以了。HDM91 2021-12-29
我不明白为什么你不能在useData的主体中使用useUser?HDM91 2021-12-29
2 个回答
#1楼 已采纳
得票数 3

正确,React钩子只能从React函数组件和其他React钩子调用。useEffect钩子的回调不是React钩子,它是一个回调。根据Rules of Hooks,不要在循环、条件或嵌套函数内调用钩子。

我建议重构useData钩子,将userId作为一个参数,用于useEffect的依赖性数组中。

const fetchData = async (userId) => {
  // code to fetch data from GraphQl
};

const useData = (userId) => {
  const [data, setData] = useState();
    
  useEffect(() => { 
    fetchData(userId)
      .then((....) => {
        // the rest of the code to set the state variable data.
      });
  }, [userId]);

  return data;
};

在函数组件中的用法。

const userId = useUser();
const data = useData(userId);

如果这是很常见的配对,就抽象成一个单一的钩子。

const useGetUserData = () => {
  const userId = useUser();
  const data = useData(userId);
  return data;
};

...

const data = useGetUserData();

尽管你可能应该只是作为一个单一的钩子来实现,如下所示。

const useGetUserData = () => {
  const [data, setData] = useState();

  useEffect(() => {
    getUserInfo()
      .then(fetchData) // shortened (userId) => fetchData(userId)
      .then((....) => {
        // the rest of the code to set the state variable data.
        setData(....);
      });
  }, []);

  return data;
};
Drew Reese 提问于2021-12-29
Drew Reese 修改于2021-12-29
#2楼
得票数 0

你不能在useEffect里面调用钩子,钩子应该总是在组件主体里面,而不是在内部函数/钩子主体里面。

import useUserId from "./UseUserId";
// ...rest of the necessary imports

const fetchData = async (userId) => {
  // code to fetch data from GraphQl}
};
const useData = () => {
  const [data, setData] = useState();
  const userId = useUser();
  useEffect(() => {
    if (userId) {
      fetchData(userId).then(setData);
    }
  }, [userId]);

  return data;
};
Rahul Sharma 提问于2021-12-29