Home > OS >  Is it possible to pass a setState function as an argument to another function?
Is it possible to pass a setState function as an argument to another function?

Time:12-16

Right now, I have a lot of my auth functions inside my screen components and I want to extract them into a handlers file. But, they rely on setting the state for some loading and results states.

How can I properly pass a setState as an argument to a function?

const handleSignIn = async (email: string) => {
  setLoading(true);
  const { error } = await supabase.auth.signInWithOtp({
    email: email,
  });

  if (error) {
    console.log(error);
    setLoading(false);
  } else {
    setLoading(false);
    navigation.navigate('VerifyOtp', { email: userEmail });
  }
};

So in this case, I want to refactor the function so it takes another argument of setLoading for example. How do I achieve this?

Thank you in advance.

CodePudding user response:

It's possible to pass just callback as in another answer, but I would prefer another way of doin this:

function useSignIn() {
  const [loading, setLoading] = useState(false);

  const handleSignIn = useMemo(async (email: string) => {
    setLoading(true);

    const { error } = await supabase.auth.signInWithOtp({
      email: email,
    });

    if (error) {
      console.log(error);
      setLoading(false);
    } else {
      setLoading(false);
      navigation.navigate('VerifyOtp', { email: userEmail });
    }
  }, [setLoading]);

  return [loading, handleSignIn];
}

By the way, I'm not sure what { email: userEmail } is. Is userEmail misprint (should be email instead) or some global variable or comes from another hook? It should be somehow handled in useMemo deps.

CodePudding user response:

The most straight forward way to go is dependency injection.

export const handleSignInFactory = (setLoading) => {
  const handleSignIn = async (email: string) => {
    setLoading(true);
    const { error } = await supabase.auth.signInWithOtp({
      email: email,
    });

    if (error) {
      console.log(error);
      setLoading(false);
    } else {
      setLoading(false);
      navigation.navigate('VerifyOtp', { email: userEmail });
    }
  };

  return handleSignIn;
}

Now in your react component:

function MyComp(props) {
  const [loading, setLoading] = useState(false);
  const handleSignIn = handleSignInFactory(setLoading);
  // ...
  return <button onClick={handleSignIn}>Sign In</button>;
}

CodePudding user response:

You can make your own custom hook and extract it into its own file

function useAuth() {
  const [loading, setLoading] = useState(false);

  async function signIn() {
    setLoading(true);
    const { error } = await supabase.auth.signInWithOtp({
      email: email,
    });

    if (error) {
      console.log(error);
      setLoading(false);
    } else {
      setLoading(false);
      navigation.navigate('VerifyOtp', { email: userEmail });
    }
  }

  return [loading, signIn];
}
  • Related