对 React 行为的一些见解将不胜感激。自定义挂钩问题

Some insight on React behavior would be appreciated. Issue with custom hook

我有一个让我困惑的小 React 例子。

您可以 运行 codesanbox

处的代码

代码很简单,有一个显示'wowzers'的组件TestComponent,调用了一个自定义钩子useCustomHook。

useCustomHook 做了三件事。它声明了一个 useState [list, set_list],然后是一个基于 list 的 useEffect 来通知何时有变化,然后是一个 1 秒的定时器来更新列表。

我所期望的是 useEffect 最初会 运行 然后一秒钟后当列表更新时它会再次 运行 。但是,它每秒更新一次。不仅如此,而且 useCustomHook 正在从 TestComponent 重新进入,重新开始该过程,并且这种情况反复发生。

有人能解释一下为什么,当列表在计时器回调中更新为 set_list 时,这会导致 TestComponent 再次(并再次)调用 useCustomHook

我自以为理解了react的使用原理,开发了很多但是很小的应用。这个简单的例子真的让我失望。任何帮助将不胜感激。

index.js中的代码如下。

import { useState, useEffect } from "react";
import React from "react";
import ReactDOM from "react-dom";

const useCustomHook = () => {
  const [list, set_list] = useState([]);
  useEffect(() => console.log("useEffect", "list updated"), [list]);
  setTimeout(() => set_list(() => []), 1000);
};

const TestComponent = () => {
  const hook = useCustomHook();
  return <span>wowzers</span>;
};

class App extends React.Component {
  render() {
    return <TestComponent />;
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

setTimeout 就在钩子 body 中...每次调用钩子时它 运行 整个 body。超时正在排队触发重新渲染的状态更新。重新呈现 运行 所有挂钩。

const useCustomHook = () => {
  const [list, set_list] = useState([]);

  useEffect(() => console.log("useEffect", "list updated"), [list]);

  setTimeout(() => set_list(() => []), 1000); // <-- unintentional side-effect!
};

What I expected was that the useEffect would initially run and then a second later it would run again when the list is updated.

setTimeout 放置在安装 useEffect 中,即空依赖数组,因此它 运行 在初始安装渲染周期后刚好出现一次。

const useCustomHook = () => {
  const [list, set_list] = useState([]);

  useEffect(() => console.log("useEffect", "list updated"), [list]);

  useEffect(() => {
    setTimeout(() => set_list(() => []), 1000);
  }, []);
};

mighty 跳过了一些步骤,而且不完全是怎么回事,它肯定会不断更新,顺序步骤可以帮助你一些

import { useState, useEffect } from "react";
import React from "react";
import ReactDOM from "react-dom";

// called every render, because function component is called every render
const useCustomHook = () => {
  
  // 4 first useState, list=[] by default, alloc memory X
  // 9,15...  useState, list=[] changed by set_list, loaded from memory X 
  const [list, set_list] = useState([]);
  // 5 register effect, callback called every time list change
  // 10,16... effect alread registered, skip
  useEffect(() => 
    // 12,18... list updated because []!==[]
    console.log("useEffect", "list updated"), [list]);
  // 6,11,17... settimeout, callback in 1 sec
  setTimeout(() => 
    // 7,13,19... update memory X, triggering rerender
    set_list(() => []), 1000);
};

// function component is called every render
const TestComponent = () => {
  // 3,8,14...
  const hook = useCustomHook();
  return <span>wowzers</span>;
};

class App extends React.Component {
  render() {
    return <TestComponent />; //2
  }
}

ReactDOM.render(<App />, document.getElementById("root")); // 1