简体   繁体   中英

Infinite loop with a custom hook with UseEffect

I'm trying to create a custom hook and I have problems with an infinite loop.

There is the piece of code that implements the custom hook on my page:

const handleOnFinish = response => {
    const {data} = response

    setIsLoading(false)
    setTableData(data)
    setPage(page)
  }

  const handleOnInit = () => setIsLoading(true)

  useEffectUseCaseTokenValidation({
    onFinish: handleOnFinish,
    onInit: handleOnInit,
    params: {nameToFilter: nameFilter, page},
    useCase: 'get_clients_use_case'
  })

And this is my custom hook:

import {useContext, useEffect} from 'react'
import Context from '@s-ui/react-context'

const noop = () => {}

export function useEffectUseCaseTokenValidation({
  onFinish = noop,
  onInit = noop,
  params = {},
  useCase = ''
}) {
  const {domain} = useContext(Context)
  const config = domain.get('config')

  useEffect(() => {
    onInit()

    domain
      .get(useCase)
      .execute(params)
      .then(response => {
        const {error} = response

        if (error && error.message === 'INVALID_TOKEN') {
          window.location.replace(config.get('LOGIN_PAGE_URL'))
        }

        onFinish(response)
      })
  }, [params]) // eslint-disable-line
}

With this, the useEffect is released again and again, instead of taking params into account. I add a console.log for params and is always receiving the same.

I was using this useCase correctly without the custom hook, so that is not the problem.

I want to use this custom hook to avoid to copy and paste the redirection on all UseEffects for all project pages.

Thank you!

The problem is the object ref, that means that you are passing {nameToFilter: nameFilter, page} as params but each time the components renders a new object ref is creating so, react compare both with the === , so if you run this code in your console

var params1 = { name: 'mike', age: 29 };
var params2 = { name: 'mike', age: 29 };
console.log(params1 === params2); // it will console false

that's because object declaration are not the same event when its key/value pairs are the same.

So to avoid infinite loop into your hook, you should use useMemo to avoid that, so try this

import { useMemo } from 'react';
const params = useMemo(() => ({ nameToFilter: nameFilter, page }), [nameFilter, page])

useEffectUseCaseTokenValidation({
  onFinish: handleOnFinish,
  onInit: handleOnInit,
  params: params,
  useCase: 'get_clients_use_case'
})

useMemo will avoid recreating object reft in each render phase of your component

Please read the useMemo react official docs

Please read this post to know the differences between values VS references comparison

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM