对 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
我有一个让我困惑的小 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