0

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!

2
  • params is a new JavaScript Object on every render, so when it's passed as a dependency to your useEffect it will always trigger it to be called again. List each of the unchanging values instead: [params.nameToFilter, params.page]. Commented Sep 23, 2019 at 20:33
  • When you disable the lint you should be sure what you are doing. Commented Sep 23, 2019 at 20:34

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

2 Comments

Best response ever! It works and I understand it. Thank you!
I glad to know that it helped you. @Aitor

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.