Home > Software engineering >  Uncaught Error: Invalid hook call. When posting data using useEffect
Uncaught Error: Invalid hook call. When posting data using useEffect

Time:10-05

I have a button that should push some data to a web server. However I am getting an error:

"Uncaught 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"

This is the code that is run when I press the submit button:

const handleSubmit = (e) => {

if (local_id != null) {

  useEffect(async () => {
    try {
      let res = await getProtectedAsset(
        "http://127.0.0.1:5002/change_settings",
        user,
        setUser,
        "testdata"
      );

      console.log(res.data);

    } catch (error) {
      console.error(error.message);
    }
  }, []);

}

}

The getProtectedAsset function is tried and tested, what is different in this case is that I want to post data when a button is pressed, in all other cases I post data on page load. I assume I am doing something wrong with how I use useEffect but from what I have read online I do not understand how I fix it.

How to I make this code run when I press the button?

Thank you for your help!

CodePudding user response:

Following the react documentation: "Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns". https://reactjs.org/docs/hooks-rules.html

I suggest you to change the code in order to have your useEffect at the top level of the component.

As I can see you are passing user and setUser to getProtectedAsset, probably a better approach would be to create a custom hook that handles that HTTP request being able to update its own state.

CodePudding user response:

The reason you're getting this error is because you're running the useEffect hook inside of an if-statement which is a no-no in the hooks rules.It says so in the error, You might be breaking the Rules of Hooks

You can read more about react hooks rule here.

If you want the code to run only when local_id is not null, then put that conditional inside the useEffect function.

For example:

const fetchData = async () => {
 try {
    let res = await getProtectedAsset(
       "http://127.0.0.1:5002 /change_settings",
      user,
      setUser,
      "testdata"
     );

     console.log(res.data);
     return res.data;

     } catch (error) {
      console.error(error.message);
     }
}

useEffect(async () => {
  if (local_id != null) {
    await fetchData();
  }

}, [local_id]);

const handleSubmit = async (e) => {
  if (local_id != null) {
    await fetchData();
  }
}

Note that I have added the local_id to the dependency array of the useEffect hook to run the hook and call the fetchData function whenever the value of the variable changes to keep the data in sync. I assumed here that this is what you wanted since you included the data fetching inside a useEffect, if on the other hand, you want to run the code only when the submit button is clicked, then the useEffect here is unnecessary, and you can remove it and only use the fetchData along with the handleSubmit.

CodePudding user response:

React Rules of Hooks: https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

Rule 1: Only Call Hooks at the Top Level

React Function Components are JavaScript functions, so any function defined in the component's body is a nested function. The answer is to change the useEffect() hook to respond to a change in state, which you perform in the form's onSubmit function:

const [submit, toggleSubmit] = useState(false);

useEffect(async (s) => {
  if (local_id && s) {
    try {
      let res = await getProtectedAsset(
        "http://127.0.0.1:5002/change_settings",
        user,
        setUser,
        "testdata"
      );

      console.log(res.data);

    } catch (error) {
       console.error(error.message);
    }
  }
}, [submit]);

return (
  <form onSubmit={() => toggleSubmit(true)}>
  </form>
);
  • Related