【问题标题】:How to stop the infinite loop inside this React useEffect?如何停止这个 React useEffect 中的无限循环?
【发布时间】:2022-11-29 13:41:10
【问题描述】:

我希望 React 从非 React 上下文呈现按键,更具体地说是字符串数组 keys

import * as React from "react";
import { render } from "react-dom";

let keys: string[] = [];

function handleKeypress(event: any) {
  keys.push(event.key);
  console.log(keys);

  // there will be more code here unrelated to React.
}

document.removeEventListener("keypress", handleKeypress);
document.addEventListener("keypress", handleKeypress);

function App() {
  const [keysState, setKeysState] = React.useState<string[]>([]);

  React.useEffect(() => {
    function updateKeysState() {
      setKeysState([...keys]);
    }

    // if you uncomment this, the code inside useEffect will run forever
    // updateKeysState()

    console.log("Hello world");
  }, [keysState]);

  return (
    <div>
      {keys.map((key: string, id) => (
        <li key={id}>{key}</li>
      ))}
    </div>
  );
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

我几乎完成了……问题是,React.useEffect 中的代码在无限循环中运行。

我认为将 [keysState] 作为第二个参数传递给 React.useEffect 会停止无限循环。但它没有。

为什么会这样以及如何解决?

直播码:https://codesandbox.io/s/changing-props-on-react-root-component-forked-eu16oj?file=/src/index.tsx

【问题讨论】:

标签: javascript reactjs typescript


【解决方案1】:

最好的方法是将非 React 代码集成到应用程序中,以便通过按键设置状态是自然而微不足道的。

function App() {
    const [keys, setKeys] = React.useState<string[]>([]);
    useEffect(() => {
        function handleKeypress(event: KeyboardEvent) {
            setKeys([...keys, event.key]);
            // There will be more code here that's unrelated to React.
        }
        document.addEventListener("keypress", handleKeypress);
        return () => {
            document.removeEventListener("keypress", handleKeypress);
        };
    }, []);

然后你可以完全放弃当前的React.useEffect(及其无限循环)。

如果那不是一个选项,您将不得不从 React 外部触发 React 状态设置器——无论您怎么看,那都会非常难看。我想你可以将它分配给一个外部变量:

let setKeysOuter;

function handleKeypress(event: KeyboardEvent) {
  setKeysOuter?.(keys => [...keys, event.key]);
  // There will be more code here that's unrelated to React.
}

function App() {
  const [keys, setKeys] = React.useState<string[]>([]);
  setKeysOuter = setKeys;

【讨论】:

  • 我想将非 React 代码保留在 React 之外。如果是这样,我该如何停止无限循环?
  • @alexchenco 你是什么意思“非反应代码”?只是 JavaScript 和 JSX 变成了 JavaScript 和 HTML,因为你想从 DOM 事件控制组件状态,所以它们应该被集成
  • @alexchenco 如果你愿意,你可以在外部声明大部分代码,然后在 React 内部,只调用状态设置器并调用外部(非 React)函数。
  • 您也可以简单地注册多个事件侦听器; React 处理组件状态和外部处理任何事情的人
  • 可能是值得的——超级 DRY 代码并不总是最可维护的选择。
【解决方案2】:

您需要将两个参数传递给 useEffect:

1 => 具有连接到该系统的设置代码的设置功能。 它应该返回一个清理函数,其中包含与该系统断开连接的清理代码。 2 => 依赖项列表,包括在这些函数中使用的组件中的每个值。

【讨论】:

    猜你喜欢
    • 2021-10-21
    • 2021-12-05
    • 1970-01-01
    • 2021-09-30
    • 2022-12-02
    • 2021-01-31
    • 2020-04-14
    • 2020-09-06
    相关资源
    最近更新 更多