reactjs 为什么useEffect在我使用props中的函数时被触发(函数没有改变)?

jjhzyzn0  于 2023-06-29  发布在  React
关注(0)|答案(3)|浏览(160)

Main组件正在调用Modal/Dialog。

[...]
  const closeDialog = () => setIsOpenDialog(false);
  return (
      <MyDialog
        isOpen={isOpenDialog}
        onClose={closeDialog}
      />
  );

MyDialog代码是:

[...]
  useEffect(() => {
    console.log('This removes dialog states (data)!')
  }, [onClose]);

export default function MyDialog({
  isOpen,
  onClose,
}) {
    return (
    <Dialog
      isOpen={isOpen}
      onClose={onClose}
      dialogTitle="Add/Edit"
      onClickCancel={onClose}
    >
    [...]
    </Dialog>
);
}

当我单击Cancel并调用onClose时,我可以看到useEffect触发。请问原因是什么?我的理解是不应该,因为onClose函数对象(来自props)没有改变。

7gs2gvoe

7gs2gvoe1#

React中的useEffect钩子会在依赖数组中的任何依赖发生变化时运行。在您的示例中,useEffect依赖于onClose属性。因此,它将在每次onClose属性更改时运行。
然而,即使onClose函数在代码中没有改变,useEffect仍然可能由于JavaScript处理函数标识的方式而运行。在JavaScript中,每次你定义一个函数,它都是一个新的示例,即使它做的是完全相同的事情。
因此,在本例中,每次组件重新渲染时,都将closeDialog定义为render函数中的新函数。这意味着,从React的Angular 来看,onClose每次都是一个新函数,它会触发useEffect
为了解决这个问题,你可以使用useCallback钩子来确保你的closeDialog函数在渲染器上有一个稳定的标识,除非它的依赖关系发生了变化:

const closeDialog = React.useCallback(() => setIsOpenDialog(false), []);

在上面的例子中,useCallback返回一个记忆化的函数版本,只有当其中一个依赖项发生变化时,它才会发生变化。在本例中,dependencies数组为空([]),这意味着closeDialog函数的标识在重新呈现时将是稳定的。

c6ubokkw

c6ubokkw2#

MyDialog组件中的useEffect钩子被触发,因为指定了依赖数组**onClose。这意味着只要onClose的值发生变化,效果就会运行。虽然onClose的函数引用在MyDialog组件的整个生命周期中保持不变,但效果不是比较函数引用本身,而是比较每个渲染周期中onClose的值。当调用onClose函数时,MyDialog组件会再次渲染,然后创建一个新的onClose函数示例。这会导致onClose的值发生变化,从而触发useEffect**钩子。

ql3eal8s

ql3eal8s3#

在JavaScript中,这个术语被称为引用相等。

示例:

  • 第一次渲染 *
// This has an address in memory: 111
const function1 = () =>{
// ...
}

因此,当react重新呈现组件时,它会重新声明这个函数

  • 第二次渲染 *
// This has an address in memory: 112
const function1 = () =>{
// ...
}

因此,如果useEffect将function1作为依赖项,则会将 Second Sender 中的声明与 First Render 中的声明进行比较。
所以它将导致111 !== 112然后根据这个条件它将重新运行useEffect。
要解决此问题:

**函数:**可以使用useCallback钩子

const function1 = useCallback(()=>{
// ...
},[])

对于对象和数组可以使用useMemo钩子

const object1 = useMemo(()=>({name: 'test user'}),[])
const array1 = useMemo(()=>([1, 2, 3, 4]),[])

相关问题