typescript React useEffect Hook即使在依赖数组中没有状态更改时也会被触发

ehxuflar  于 2023-05-08  发布在  TypeScript
关注(0)|答案(3)|浏览(218)

在我的React组件中,我希望只有当某些状态发生变化时才触发某些操作。我将状态初始化为一个默认值,并将其放入钩子的依赖数组中。在会话期间,我根本不会改变这种状态。但是,React在组件首次挂载后仍然会运行useEffect钩子。
我想知道它为什么会这样。有没有一种优雅的方式(或者最佳实践是什么)来实现这一点?谢谢你的帮助!
代码如下所示:

import React from 'react';

export function App(props) {
  const [testString, setTestString] = React.useState('abc');
  console.log(testString);
  React.useEffect(() => {
    console.log('******* I am not supposed to log here !!!')
  }, [testString]);

  return (
    <div className='App'>
      <h1>Hello React.</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

也可在www.example.com上获得playcode.io:https://playcode.io/1458690

db2dz4w8

db2dz4w81#

根据documentation for useEffect
当你的组件第一次被添加到DOM时,React会运行你的设置函数。在每次使用更改的依赖项重新渲染之后,React将首先使用旧值运行cleanup函数(如果您提供了它),然后使用新值运行setup函数。
可以使用ref存储组件是否已装载,以区分初始渲染和更新。
参见:Equivalent to componentDidUpdate using React hooks

cunj1qz1

cunj1qz12#

监听组件何时在其他useEffect之前挂载(useEffect with empty dependency array)(它们按顺序运行)并在那里设置一个标志...我不知道它有多优雅,但它很有效:

import React from 'react';

export default function App(props) {
  const [testString, setTestString] = React.useState('abc');
  console.log(testString);

  let justMounted;
  React.useEffect(() => { justMounted = true }, []);

  React.useEffect(() => {
    if (justMounted) { return; }
    console.log('******* I am not supposed to log here !!!')
  }, [testString]);

  return (
    <div className='App'>
      <h1>Hello React.</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}
0pizxfdo

0pizxfdo3#

useEffect钩子的默认行为是,它总是在组件第一次挂载时被调用。无论是否包含依赖关系数组,情况都是如此。这就是为什么你得到了你的问题中描述的行为。
如果包含了依赖数组,那么只要该数组中的某个依赖项发生更改,就会调用useEffect。如果不包含依赖项数组,则useEffect将仅在组件首次装入时调用一次。
您可以使用useRef钩子来创建一个变量,比如const firstRender = useRef(),它跟踪是否是第一次渲染。在useEffect内部检查firstRender.current是否为true,如果是,则将其设置为false并返回useEffect,而不运行任何其他代码。如果firstRender.current为false,则执行您希望在useEffect中执行的操作。

const firstRender = useRef(true);
React.useEffect(() => {
  if (firstRender.current) {
    firstRender.current = false;
    return;
  }
  console.log('******* I am not supposed to log here !!!')
}, [testString]);`

相关问题