0

I've been trying to solve a problem for 4 days and I've searched and searched a lot! I'm not sure if I'm just searching for the wrong thing or seeing it and am just completely oblivious to it. My problem is that when I call the hook from the main function, it works, but when I call it via an onSubmit function, it fails for invalid hook call. I understand the concept of why the hook would be invalid, but am just completely unsure how to resolve it. I reformatted my hook so that I could initialize it earlier in my code and then call it via the onSubmit, but the problem is that the state token only gets updated on initialization and not whenever it's changed. Thus leading to some API calls with a bad token. Any Help Anyone can offer will be greatly appreciated!

The Setup: NextJS, React-Form, Redux via Next-Redux-Wrapper, SWR

When ReactForm validates the form, I'd like for it to submit it's data to a custom hook. However, that custom hook fails with the Invalid Hook Call. It does it as soon as I defined a variable for useState.

-- Form Code ---

const { register, errors, handleSubmit, setValue, reset, control } = useForm()
<form onSubmit={ handleSubmit(onSubmit) }>

-- onSubmit Code ---

const onSubmit = (data) => {
   const newData = useApiPost(`users/update/${ id }`, submitData)
}

-- Custom Hook --

function useApiPut(resource, params){
   const [ data, setData ] = useState(null)
   const [ error, setError ] = useState(null)

   const { url, data : inData } = rest(resource, params)

   //Post data
   const { data : resData, error : resError, mutate } = useSWR(
      state.user.token ? url : null,
      url => axios.request({
            url,
            method : 'post',
            data : inData,
            headers : { Authorization : `Bearer ${ state.user.token }` }
         })
         .then(({ data }) => data),
      { revalidateOnFocus : false }
   )

   useEffect(() => {
      if(resData) {
         setData(resData)
      }
      if(resError) {
         setError(resError)
      }
   }, [ resData, resError ])

   return { data, error, mutate }
}
  • Where is `handleSubmit`? You are not binding `onSubmit` correctly. – Sinan Yaman Oct 20 '21 at 20:28
  • It's coming from react-hook-form, I've updated my code to properly show this. Thank you in advance for your help! – user2833257 Oct 20 '21 at 20:45
  • Hi my friend... Can you please change this `
    ` to this `
    handleSubmit(onSubmit) }>` and test again? Thanks.
    – Ali Briceño Oct 20 '21 at 23:00
  • Thank you @AliBriceño, I did, unfortunately, it didn't solve the problem! :( I really appreciate your help! – user2833257 Oct 20 '21 at 23:11
  • Ok don't worry it was just to check. Let me create a new project in order to try to reproduce your problem. Sinceriously, I never was seeing this kind of hook implementation. But let's dig on this bro! – Ali Briceño Oct 20 '21 at 23:21
  • 1
    This part is not working on my brain xD: `const onSubmit = (data) => { const newData = useApiPost(`users/update/${ id }`, submitData) }` why do you call your hook like this? Usually all hooks are declared besides the state vars and not inside a function. Then, on the function you work with the values exposed on the `return` of your hooks... – Ali Briceño Oct 20 '21 at 23:29
  • Also, in your custom hook code I think there is a mistake, you call it like `useApiPut` but on the onSubmitCode it call it like `useApiPost `... are this correct? – Ali Briceño Oct 20 '21 at 23:40
  • @user2833257 Hooks should only be called at the top level of a React component/another React hook. Don't call hooks inside loops, conditions, or nested functions. See [Rules of Hooks](https://reactjs.org/docs/hooks-rules.html). – juliomalves Oct 21 '21 at 07:45

1 Answers1

0

So the answer to this ended up being a few different things.

First, accessing my store value via store.getState() resolved one issue with hooks.

Secondly, moving away from SWR. It is an AWESOME wrapper and capable of a TON, no doubt. I just kept struggling with it and finally gave up. I moved to using Axios Interceptors and it has been amazing. Axios doesn't cache (out of the box) like SWR, but I was utilizing the caching for tokens, so I wasn't really using it to it's full potential. Please note, I'm in no way bashing SWR, it's a really great and extremely powerful library.

Lastly, wrapping the entire set of hooks into one function allowed me to initialize the function at the root of my page and then access the hooks I needed to use later.

So instead of just calling useApiPost() now my hook looks like this:

const useApi = async() => {
   const post = async() => {
      //Do work here
   }
   return { post }
}

export default useApi

Then it's called like this inside the main function:

const { post } = useApi()

And it's called like this in the onSubmit Function:

const options = await post(resource, params)
  • It is not recommended using hooks inside regular JS functions. https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level – Mike S. Oct 21 '21 at 16:22