Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

283
Visualizações
Custom react hook with useeffect, cant use in non-component function

I made a custom react hook, which has a useEffect and, for now, returns a set of different states. It's a hook for axios, and the gist of it is this:

export default function useAxios({ url, data = {}, method = "GET"} ) {
  var [loading, setLoading] = useState(true)
  var [data, setData] = useState(null)

  useEffect(function() {
    (async function() {
      // do axios request and set loading and data states
    })()

    return () => // cleanup function that cancels axios request
  }, [])

  return {
    loading,
    data
  }
}

Now, in a simple component I can easily use this custom hook - but my question is: What if I want to use my hook inside an event handler, say:

export default MyComponent() {
  function handleSubmit(e) {
    var { data } = useAxios({
      url: "/my-end-point",
      data: {
        testInput: e.target.testInput.value
      }
    })
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="testInput" />
      <button type="submit">Submit</button>
    </form>
  )
}

Problem is my useAxios hook has a useEffect, and so I cannot use it inside a non-component function, i.e. handleSubmit. So what is the work around? Is there even one? Thanks in advance.

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

As to React's Only Call Hooks from React Functions, you should always:

✅ Call Hooks from React function components.
✅ Call Hooks from custom Hooks.

Fail to satisfy these two rules leads to unexpected render result out of React.

With those rules in mind, you should return a submitHanlder from react hook instead of just passing the hook function into another component as a callback function.

I might guess that your intention is to trigger the axios request on the submit event. If so, it is possible to achieve that without passing whole hook into event handler.

First of all, as the rules say, you have to make sure your hook got called in every render. So the MyComponent can be rewrite in the below way:

export default function MyComponent() {
  var startRequest = useAxios({url: "/my-end-point"}) //<---- useAxios now returns the startRequest function, and will always be called on every render

  return (
    <form onSubmit={(e) => {
      e.preventDefault()
      startRequest({testInput: e.target.testInput.value})  // <----- call your startRequest here in the submit hanlder
      .then(data => {
        //process your data here
      })
    }}>
      <input type="text" name="testInput" />
      <button type="submit">Submit</button>
    </form>
  )
}

Please note that now the hook returns a function startRequest which you can put in your handler, and trigger that handler any time appropriated.

And rearrange your hook's code like below:

export function useAxios({ url, method = "GET"} ) {
  var [loading, setLoading] = useState(true)  
                                            // <------ no setData here

  var startRequest = async function(body = {}) { // <------ Move your input here
    // do axios request and set loading and data states
    setLoading(true)
    await data = axios.post(body)
    setLoading(false)
    return data             // <------- return data as promise
  }

  var cancelRequest = () => // cleanup function that cancels axios request

  useEffect(function() {
    return cancelRequest
  }, []) // useEffect only helps your cancel request on unmounted.

  return startRequest
}

The useEffect now only helps you cleanup axios request without the need to start one, since firing a request should be an event handler's job.

And since the data return by axios is in a promise, you don't need to explicitly setData to store your response data so I removed the line of useState(null).

about 4 years ago · Juan Pablo Isaza Relatório

0

I would take a look at popular libraries like SWR (useSWR) and apollo-client (useQuery). They're approach is something like this when making get requests

const MyComponent = () => {
  const [shouldSkip, setShouldSkip] = useState(true);
  const queryResult = useQuery('my-url', {skip: shouldSkip});

  const handleSubmit = () => {
    setShouldSkip(false);
    // this will cause the component to rerender, and skip will now be false
  }

}

When making post requests, its something like this:

const MyComponent = () => {
  //useMutation returns a callable function whenever you want
  const callFunction = useMutation('my-url');

  const handleSubmit = () => {
    await callFunction()
  }

}

You can also take a look at axios-specific hooks like https://github.com/simoneb/axios-hooks, another common pattern they use is to include a refetch function as a result of the hook, that can be called at anytime (like in an event handler)

about 4 years ago · Juan Pablo Isaza Relatório

0

The point of the hook is not to make the request for you, the point of the hook is to communicate the internal state of stuff (the axios request, in your case) to the component, so that you can render stuff based around that state (like loading states, or the data).

In your case, you can change the value of the query based on the component state, and have the hook return the data to the component based on its parameters. Something like this:

const useAxios = ({ query }) => {
    var [loading, setLoading] = useState(true)
    var [data, setData] = useState(null)

    useEffect(function () {
        (async function () {
            setLoading(true)
            // do axios request and set loading and data states
            const request = await axios.get('endpoint', { query })

            setData(request.data)
            setLoading(false)
        })()

        return () => { }// cleanup function that cancels axios request
    }, [])

    return {
        loading,
        data
    }
}

const Component = () => {
    const [query, setQuery] = useState('')
    const { loading, data } = useAxios({ query });

    const submitHandler = (event) => { setQuery(event.target.testInput.value) }

    return (
        <>
            <form onSubmit={submitHandler}>
                <input name="testInput" />
                <input type="submit" />
            </form>
            {loading && (
                <>a spinner</>
            )}
            {data && (
                <DataRenderer data={data} />
            )}
        </>
    )
}
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda