Daniel Nduka
Daniel Nduka

Reputation: 7

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. custom hooks with nested functions

i have created a custom React Hook that has a function that will dispatch an action to redux store.

import { useDispatch, useSelector } from "react-redux";
import { toggle } from "../state/reducers/togglePassSlice";

const useToggle = () => {
  const { showpass } = useSelector((state) => state.toggle);
  const dispatch = useDispatch();

  const togglePassVisibility = () => {
    // console.log(showpass);
    dispatch(toggle(showpass));
  };

  return { togglePassVisibility };
};

export default useToggle;

on my component when i try to call it, i get an error: Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

import EntryCard from "../../components/EntryCard/EntryCard";
import InputGroup from "../../components/InputGroup/InputGroup";
import Input from "../../components/Input/Input";
import Button from "../../components/Button";
import { EntryPage, PageHader } from "./style";
import { Link } from "react-router-dom";
import useToggle from "../../hooks/useToggle";

const SignInPage = () => {
  const { togglePassVisibility } = useToggle();

  const toggle = togglePassVisibility();

  return (
    <EntryPage>
      <PageHader to="/">AWESOME LOGO</PageHader>
      <EntryCard>
        <h2>login</h2>
        <form>
          <InputGroup>
            <label htmlFor="email">Email</label>
            <Input type="email" placeholder="Enter email" id="email" />
          </InputGroup>
          <InputGroup>
            <label htmlFor="password">Password</label>
            <Input type="password" placeholder="Enter password" id="password" />
          </InputGroup>
          <Button type="submit" full="true">
            Sign in
          </Button>
        </form>
        <span>
          Dont have an account?
          <Link to="/signup"> Sign up</Link>
        </span>
      </EntryCard>
    </EntryPage>
  );
};

export default SignInPage;

how do i solve this error and pls🙏 what is a better way for this approach with custom hooks

Upvotes: 0

Views: 328

Answers (1)

samthecodingman
samthecodingman

Reputation: 26226

Looking at these lines in particular:

const SignInPage = () => {
  const { togglePassVisibility } = useToggle();

  const toggle = togglePassVisibility(); // this calls dispatch every render!

  return ( /* ... render ... */ );
}

Every time your component is rendered, you immediately call togglePassVisibility() which will cause a new render. This is an infinite loop.

If you instead want to be able to call togglePassVisibility as if it were called toggle, you can do one of the following:

  • don't invoke it when assigning it to toggle:
const toggle = togglePassVisibility; // <-- no parentheses
  • assign it using deconstruction:
const { togglePassVisibility: toggle } = useToggle();
  • in your hook, export an array instead:
// in hooks file
const useToggle = () => {
  /* ... */
  return [ togglePassVisibility ];
};

// in component
const [ toggle ] = useToggle();

Note: Don't forget to bind toggle to a button.

Upvotes: 3

Related Questions