带有UseEffect的自定义挂钩的无限循环

时间:2019-09-23 20:24:02

标签: javascript reactjs

我正在尝试创建一个自定义钩子,并且遇到无限循环问题。

有一段代码实现了我页面上的自定义钩子:

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'
  })

这是我的自定义钩子:

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
}

这样,useEffect就会一次又一次地释放,而不是考虑参数。我为参数添加了console.log,并且总是收到相同的参数。

我在没有自定义钩子的情况下正确使用了useCase,所以这不是问题。

我想使用此自定义钩子以避免在所有项目页面的所有UseEffects上复制和粘贴重定向。

谢谢!

1 个答案:

答案 0 :(得分:1)

问题是对象ref,这意味着您将{nameToFilter: nameFilter, page}作为参数进行传递,但是每次组件渲染新的对象ref时都在创建,因此,将两者与===进行比较,如果您可以在控制台中运行此代码

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

那是因为当对象的键/值对相同时,对象声明不是同一事件。

因此,为避免无限循环进入钩子,应使用useMemo来避免这种情况,因此请尝试

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将避免在组件的每个渲染阶段重新创建对象放样

请阅读useMemo react official docs

请阅读此post,以了解值与引用比较之间的区别