【问题标题】:React useEffect rendering more than onceReact useEffect 渲染不止一次
【发布时间】:2021-03-18 02:46:45
【问题描述】:

我是 Hooks 的新手。我用componentDidMount编写了一个项目。

现在我正在学习钩子并用钩子重写这个项目。我想先获取数据并在控制台上打印。
但是,它渲染了 3 次。可能是因为我在useEffect中使用了2个setState。但是,在其中一个中,我将数据设置为数据数组,而在另一个中,我保留了微调控件的加载值。我怎样才能像componentDidMount 一样使用useEffect 一次来提取数据并设置我的状态?

当我将控制台写入useEffect 时,“React Hook useEffect 缺少依赖项:'data'。”警告并返回一个空列表。

顺便说一句,我删除了严格模式。

import React, { useState, useEffect } from "react";
import axios from "axios";

function App() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      const { data } = await axios.get("/data/data.json");
      setData(data);
      setLoading(false);
    };
    fetchData();
  }, []);
  console.log(data);
  return <div className="App">App</div>;
}

export default App;

【问题讨论】:

  • useEffect 没有多次运行,它是重新渲染的组件。重新渲染本质上没有任何问题,但在这种情况下,流程是 (1) 组件渲染 (2) useEffect 运行,调用 fetchData (3) fetchData 调用 setData (4) 组件第二次渲染,因为 @ 987654334@ 已更改。
  • 这段代码工作正常吗?我怎样才能运行一次?
  • 看来是正确的。多次调用您的console.log 不是错误,这是意料之中的。
  • 您有两个data 变量(一个来自useState,一个用于API 调用)。这可能会导致冲突。我建议更改一个名称。
  • &GalAbra 我认为您就像问题所有者一样感到困惑......再次阅读 cmets..

标签: javascript reactjs react-hooks use-effect use-state


【解决方案1】:

我认为两次使用 data 变量可能会导致与 linter 发生冲突。您可以重命名来自 API 调用的数据以防止出现以下警告:“React Hook useEffect has a missing dependency: 'data'.”

您的组件将在每次状态更新时重新渲染,但 useEffect 只会在您的依赖项更改时运行。由于它们不会改变,API 调用只发生一次。

为了证明这一点,您可以将console.log(result) 移动到您的useEffect 中,并且只看到它记录一次。但是,请确保在 result 而不是 data 上调用它,因为在调用 setData 之后,直到下一次渲染时才会更新状态。

import React, { useState, useEffect } from "react";
import axios from "axios";

function App() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      const { data: result } = await axios.get("/data/data.json");
      setData(result);
      setLoading(false);
      console.log(result); // runs once
    };
    fetchData();
  }, [setData, setLoading]);

  console.log(data); // runs 3 times
  return <div className="App">App</div>;
}

export default App;

【讨论】:

  • 为什么要写“[setData, setLoading]”作为useEffect的参数?当我在其他地方再次更改加载状态时,它会再次调用 useEffect。我希望 useEffect 只工作一次,用于从 api 或其他东西获取数据。你能解释一下吗?
  • 我添加这些是因为它们是您的 useEffect 的依赖项,这意味着您在 useEffect 正文中使用这两个变量。如果您没有将 useEffect 正文中的所有变量都放在依赖项数组中,则 linter 通常会抱怨。但是,由于这两个函数永远不会改变,它们永远不会触发重新渲染。加载的变化不会导致再次调用useEffect,函数setLoading在依赖数组中,而不是loading
【解决方案2】:

组件在每次状态更新后正常重新渲染。
因此,在您的示例中,它会在更新 data 的值时重新渲染,并在更新 loading 时重新渲染。

请检查此demo 以检查每次状态更改后渲染是如何发生的:

  1. 初始渲染
  2. loading 设置为true 之后
  3. data 被获取并设置后
  4. loading 设置为false 之后

【讨论】:

    猜你喜欢
    • 2022-11-26
    • 2020-07-06
    • 2020-08-16
    • 2020-01-11
    • 2021-09-29
    • 1970-01-01
    • 2020-04-23
    • 2020-01-06
    • 2021-02-17
    相关资源
    最近更新 更多