我是react 的新手,我正在阅读这篇article,以了解如何react 呈现机制.我遇到了这个例子:

function App() {
  const [body, setBody] = React.useState()
  const [status, setStatus] = React.useState('idle')

  const fetchConfig = {
    method: 'POST',
    body,
    headers: {'content-type': 'application/json'},
  }
  const makeFetchRequest = () => (body ? fetch('/post', fetchConfig) : null)

  React.useEffect(() => {
    const promise = makeFetchRequest()

    // if no promise was returned, then we didn't make a request
    // so we'll exit early
    if (!promise) return

    setStatus('pending')

    promise.then(
      () => setStatus('fulfilled'),
      () => setStatus('rejected'),
    )
  }, [makeFetchRequest])

  function handleSubmit(event) {
    event.preventDefault()
    // get form input values
    setBody(formInputValues)
  }

  return (
    <form onSubmit={handleSubmit}>
      {/* form inputs and other neat stuff... */}
    </form>
  )
}

作者表示,这App个组件将导致无限渲染:

猜猜会发生什么事.如果你猜"离家出走 副作用循环"你说得对!原因是因为React.useEffect 将触发对给定效果回调的调用 依赖项数组的元素会更改.我们唯一的依靠就是 在组件中创建了MakeFetchRequest和MakeFetchRequest. 这意味着每一次渲染都是新的.

我想用一个更简单的例子来模拟这种行为:

import { useEffect, useState } from 'react';

const App = () => {
  const [state, setState] = useState(0);

  const fn = () => {
    setState(1);
  };

  useEffect(() => {
    console.log('side effect');
    fn();
  }, [fn]);
};

export default App;

我期待无限的渲染,因为在组件重新渲染之后,调用fn会导致state更改,这会导致重新渲染,这会导致新的fn实例,这应该会导致重新渲染,因为我们依赖于它,这会继续进行,但这不是正在发生的事情.useEffect钩子似乎只执行两次.但在作者的例子中,它会导致无限循环.我不确定我在这里理解错了什么

Updated

我想我现在明白了.

Author's case

useEffect钩子执行时.它将status设置为挂起,并且在异步操作之后,status被再次设置为"已完成"或"被拒绝",因此App组件被再次执行,其中makeFetchRequest的新实例导致组件重新呈现,依此类推.

My case

useEffect钩子第一次呈现,调用fn并更改state,这会导致重新呈现和一个新的fn实例,但这里的REACT识别出实现保持不变,因此它不会重新呈现组件

推荐答案

除非在组件外部声明函数(即稳定引用),否则Reaction会将作为依赖项传递的函数视为在每个呈现上使用Effect的新引用.这意味着Reaction会分析函数引用以决定是否重新执行效果,即使理论上在每次渲染时都会重新创建FN.

由于示例中的FN在每次渲染时重新生成,因此Reaction会将其识别为新引用.然而,由于FN的实现保持不变,Reaction认为这不是一个足够大的更改,不会导致该效果再次发生.

在本文提供的示例中,makeFetchRequest被直接提供给useEffect's依赖项array.Reaction将其视为新引用并将其视为更改,因此即使在每次渲染时重新创建它,它仍具有相同的效果.

在try 中,您在依赖项数组中输入了fn.Reaction也将fn视为新引用,因为它是为每次渲染重新创建的.但在您的示例中,由于重新生成fn对效果中的逻辑影响不大,因此Reaction不会强制在每次渲染时都发生该效果.Reaction不会重新运行效果,因为它足够智能,可以意识到即使FN重新生成,其行为也不会改变.

因此,Reaction根据它们是否是稳定的引用来处理dependencies differently,这解释了为什么您在第一次try 中看到的行为不同于本文中描述的行为.Reaction将makeFetchRequest解释 for each 呈现上的新引用,这就是本文示例中的效果无限激活的原因.

Reactjs相关问答推荐

导致类型错误的调度不是函数";

安装后未渲染tailwind

cypress 不能点击SPAN

如何使用Reaction Testing Library+Vitest正确更新单元测试中的输入?

有没有可能在next.js和ssr中使用tsps?

当我无法引用模态组件时,如何使模态组件在 Next.js/React 中管理自己的状态?

在 React 中是否有任何理由要记住 Redux 操作创建者?

.populate() 方法在 mongodb 中不起作用

Next.js `getLayout` 函数没有被调用

React Context API 在 Next.js 中更改路由时获取默认数据

为什么 useEffect 的初始化对于加载 localStorage 不起作用?

useEffect内部的RETURN语句在首次按钮点击事件中似乎无效的原因是什么?

将水平滚动视图添加到底部导航选项卡

React Native应用如何订阅Supabase的实时数据?

当 React 中的状态发生变化时如何停止重新加载谷歌 map ?

需要先填写依赖输入字段,以便其他人工作

当每个元素都可拖动时,移动设备上的滚动列表出现问题

我如何在所有组件中使用 Chakra UI toast?

list 组件未按预期运行

如何使图标适合 react-bootstrap 中的行元素