admin管理员组

文章数量:1278793

I am using React-native and in it, I have a custom Hook called useUser that gets the user's information from AWS Amplify using the Auth.getUserInfro method, and then gets part of the returned object and sets a state variable with it. I also have another Hook called useData hook that fetches some data based on the userId and sets it to a state variable.

useUser custom-Hook:

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
   }

When I try to do this I get an error telling me

*Error: Invalid hook call. Hooks can only be called inside of the body of a function ponent. 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 for tips about how to debug and fix this problem.*

I think the problem is that I am calling the Hook useUser inside of the use effect, but using it inside the function will cause the problem described here, and I can't use it outside the body of the fetchData since the useData itself is a hook, and it can be only used inside a functional ponent's or Hook's body. So I don't know how to find a way around this problem.

I am using React-native and in it, I have a custom Hook called useUser that gets the user's information from AWS Amplify using the Auth.getUserInfro method, and then gets part of the returned object and sets a state variable with it. I also have another Hook called useData hook that fetches some data based on the userId and sets it to a state variable.

useUser custom-Hook:

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
   }

When I try to do this I get an error telling me

*Error: Invalid hook call. Hooks can only be called inside of the body of a function ponent. 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/link/invalid-hook-call for tips about how to debug and fix this problem.*

I think the problem is that I am calling the Hook useUser inside of the use effect, but using it inside the function will cause the problem described here, and I can't use it outside the body of the fetchData since the useData itself is a hook, and it can be only used inside a functional ponent's or Hook's body. So I don't know how to find a way around this problem.

Share Improve this question asked Dec 29, 2021 at 6:44 Ramin ZandvakiliRamin Zandvakili 1791 gold badge2 silver badges13 bronze badges 2
  • why are you insist to wrap simple fetch inside a hook ? just call getUserInfo inside useData hook – HDM91 Commented Dec 29, 2021 at 6:52
  • I dont understand why you can't use useUser in the body of useData ? – HDM91 Commented Dec 29, 2021 at 6:54
Add a ment  | 

2 Answers 2

Reset to default 7

Correct, React hooks can only be called from React function ponents and other React hooks. The useEffect hook's callback isn't a React hook, it's a callback. According to the Rules of Hooks, don't call hooks inside loops, conditions, or nested functions.

I suggest refactoring the useData hook to consume the userId as an argument, to be used in the dependency array of the 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;
};

Usage in Function ponent:

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

If this is something that is monly paired, abstract into a single hook:

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

...

const data = useGetUserData();

Though you should probably just implement as a single hook as follows:

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

You can't call hook inside useEffect, Hook should be always inside ponet body not inside inner function/hook body.

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

本文标签: