Home > Blockchain >  Custom React-native Hook runs the component that calls it twice. I don't understand why
Custom React-native Hook runs the component that calls it twice. I don't understand why

Time:12-29

I am trying to learn to work with custom Hooks in React-native. I am using AWS Amplify as my backend, and it has a method to get the authenticated user's information, namely the Auth.currentUserInfo method. However, what it returns is an object and I want to make a custom Hook to both returns the part of the object that I need, and also abstract away this part of my code from the visualization part. I have a component called App, and a custom Hook called useUserId. The code for them is as follows:

The useUserId 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("");
  const userId = getUserInfo();

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

  return id;
};

export default useUserId;

The App component:

import React from "react";
import useUserId from "../custom-hooks/UseUserId";

const App = () => {
  const authUserId = useUserId();
  console.log(authUserId);

However, when I try to run the App component, I get the same Id written on the screen twice, meaning that the App component is executed again.

The problem with this is that I am using this custom Hook in another custom Hook, let's call it useFetchData that fetches some data based on the userId, then each time this is executed that is also re-executed, which causes some problems.

I am kind of new to React, would you please guide me on what I am doing wrong here, and what is the solution to this problem. Thank you.

CodePudding user response:

The issue is likely due to the fact that you've declared userId in the hook body. When useUserId is called in the App component it declares userId and updates state. This triggers a rerender and userId is declared again, and updates the state again, this time with the same value. The useState hook being updated to the same value a second time quits the loop.

Bailing out of a state update

If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.)

Either move const userId = getUserInfo(); out of the useUserId hook

const userId = getUserInfo();

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

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

  return id;
};

or more it into the useEffect callback body.

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

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

  return id;
};

and in both cases remove userId as a dependency of the useEffect hook.

CodePudding user response:

Replace userId.then with to getUserId().then. It doesn't make sense to have the result of getUserId in the body of a component, since it's a promise and that code will be run every time the component renders.

  • Related