theastronomist
theastronomist

Reputation: 1056

Invalid Hook Call for Button to submit form

I have a button that is supposed to submit a form to an API. I am getting an error:

Error: Invalid hook call. Hooks can only be called inside of the body of a function...

My entire code is here:

function SubmitButton(props) {
  function SendData(url) {
    const [data, setData] = useState([]);
    const eta = document.getElementById('eta_value')
    async function getData() {
      const options ={
          method : 'POST',
          headers: {
              'Accept': 'application/json',
              'Content-Type': 'application/json;charset=UTF-8'
            },
          body: JSON.stringify({
            name:'26',
            eta:'30',
          })
      }
      const response = await fetch(url, options)
          .then(response =>{
              console.log(response.status);
          });
    }
    useEffect(() => {//check this out
      getData();
    }, []);
  };
  const title = props.title;
  //const onSubmit = {SendData}
  return(
      <div id={title}>
        <Button 
        onClick={() => SendData("http://XXX.X.X.X:XXXX/api/")} 
        variant="contained" 
        color="primary">
        </Button>
      </div>
  )
}
export default SubmitButton

It shows the error originates at:

function SendData(url) {
    const [data, setData] = useState([]);
    const eta = document.getElementById('eta_value')
    async function getData() {

Which is called by onClick. I troubleshooted for several days, but cannot figure out why I am breaking the rules of hooks.

Upvotes: 0

Views: 1515

Answers (2)

Max
Max

Reputation: 2036

Your hooks calls must be on the top level of your render function(react hook rules), not inside of SendData function

function SubmitButton(props) {
  const [data, setData] = useState([]); 
  function SendData(url) {
    const eta = document.getElementById('eta_value')
    async function getData() {
      const options ={
          method : 'POST',
          headers: {
              'Accept': 'application/json',
              'Content-Type': 'application/json;charset=UTF-8'
            },
          body: JSON.stringify({
            name:'26',
            eta:'30',
          })
      }
      const response = await fetch(url, options)
          .then(response =>{
              console.log(response.status);
          });
    }  
  };
  useEffect(() => {
    getData();
  }, []);
  const title = props.title;
  //const onSubmit = {SendData}
  return(
      <div id={title}>
        <Button 
        onClick={() => SendData("http://XXX.X.X.X:XXXX/api/")} 
        variant="contained" 
        color="primary">
        </Button>
      </div>
  )
}
export default SubmitButton

And you'd better move code that fetches data outside of render function, for the sake of readability.

Upvotes: 1

Itai
Itai

Reputation: 211

The problem is that you are using the useState hook within a nested function (your sendData() function).

As the Rules of Hooks documentation reads:

Only Call Hooks at the Top Level

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls. (If you’re curious, we’ll explain this in depth below.)

To fix this, move your const [data, setData] = useState([]); statement and the useEffect() hook to the top level of your functional component.

Hope this helps.

Upvotes: 4

Related Questions