UseEffect 被多次调用

nkt*_*nto 16 javascript fetch reactjs fetch-api use-effect

我认为 useeffect 仅在渲染后调用一次,但它被多次执行,而不是按我预期的顺序执行。我希望它在提取过程中 msg 'data loading' ,然后一旦提取完成,呈现标题字段并警告“..Done...”一次,这应该是结束。我在两个点​​添加了 ALERT 和控制台日志来确定流程,并且警报和控制台日志都以不同的顺序出现不止一次。您能否运行此代码并查看行为。我将第二个参数数组保留为空以使其仅运行一次但无济于事。

其次,请澄清是否反应渲染意味着在屏幕上显示?LOAD 表示什么阶段?什么时候显示完成??

代码如下:

import React, { useEffect, useState } from "react";
//import "./App.css";

function DemoFetchZ() {
  let data = { title: "Waiting for Data" };
  const [todo, setTodo] = useState(data);
  const [isData, setData] = useState(false);
  const [isFetching, setFetching] = useState(false);

  useEffect(() => { // called after the first render
    async function fetchData() {
      setFetching(true);
      const response = await fetch(
        "https://jsonplaceholder.typicode.com/todos/1"
      );
      console.log("response = ", response);
      let data = await response.json();
      setTodo(data); //updt state
        setFetching(false);
        setData(true)
      console.log("Data = ", data);
    }
    fetchData();
  }, []); //[isData] null value will execute once only?

  if (isFetching) {
      console.log("data loading ......")
      alert ("data loading")
      return (<div>...Data Loading.....</div>);
  }

  return (
    <div>
           - Fetch
          <br /> {alert("..DONE...")}
      <span>Title: {todo.title}</span>
    </div>
  );
}

export default DemoFetchZ;
Run Code Online (Sandbox Code Playgroud)

感谢您的帮助,

Bin*_*ese 31

对于未来的读者。

React 18 引入了对严格模式的新的仅开发检查。每当第一次安装组件时,这项新检查都会自动卸载并重新安装每个组件,并在第二次安装时恢复之前的状态。

在这种情况下,useEffect 回调在初始渲染中运行两次。状态更改后,组件渲染两次,但效果应该运行一次。

阅读官方 React 文档以获取更多故障排除信息

阅读此链接链接了解更多详细信息。


gdh*_*gdh 23

useEffect在每个渲染周期执行一次,但是您的多个状态更新useEffect会导致重新渲染。因此,您会收到很多警报。

查看代码演示并查看 console.logs 以及注释

还要注意useEffect

  • 当您提供空数组依赖项时,您的 useEffect 执行一次
  • 当您将某些值作为依赖项(例如[name]:)时,您的 useEffect 在名称 state/prop 更改时执行
  • 如果您不提供任何依赖项,则 useEffect 在每次重新渲染时执行。

在此处阅读重新渲染


小智 23

如果您刚刚使用 Create React App 创建了一个新项目或更新到 React 版本 18,您会注意到 useEffect 钩子在开发模式下被调用两次。无论您使用 Create React App 还是升级到 React 版本 18,情况都是如此。在本文中,我们将了解 React 18 的严格模式中的 useEffect 钩子,它有一个奇怪的行为。2022 年 3 月引入 React 18 时,useEffect 钩子的标准行为被修改。如果您的应用程序在更新到 React 18 后表现得很奇怪,这仅仅是因为 useEffect 钩子的原始行为已更改为执行效果两次而不是一次。

如果我们使用 useEffect 钩子,如下所示:

useEffect(() => {
  console.log("First call on mount..");

  return () => console.log("Cleanup..");
}, []);
Run Code Online (Sandbox Code Playgroud)

控制台的输出应如下所示:

First call on mount..
Cleanup..
First call on mount..
Run Code Online (Sandbox Code Playgroud)

useEffect 钩子只应在第一次挂载时调用,但它被调用了两次。

现在,如果我们需要使用 useEffect 钩子来获取数据,这样就不会获取两次怎么办?解决此行为的一个简单方法是禁用严格模式。打开 src/index.js 文件并删除 StrictMode 高阶组件:

import React, { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

import App from './App';

const rootElement = document.getElementById('root');
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);
Run Code Online (Sandbox Code Playgroud)

  • 禁用 StrictMode 会产生什么后果? (3认同)
  • 这个方法对我不起作用 (2认同)

Ser*_*ati 10

像这样重构它。

import React, { useEffect, useState } from "react";
//import "./App.css";

const DemoFetchZ = () => {
  const [todo, setTodo] = useState({});
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = () => {
    setLoading(true);
    fetch("https://jsonplaceholder.typicode.com/todos/1")
      .then((response) => response.json())
      .then((data) => {
        setTodo(data);
        setLoading(false);
      })
      .catch((error) => {
        console.log(error);
        setLoading(false);
      });
  };

  return (
    <>
      {loading ? (
        <div>...Data Loading.....</div>
      ) : (
        <div>
          - Fetch
          <br />
          <span>Title: {todo ? todo.title : "no Title Found"}</span>
        </div>
      )}
    </>
  );
};

export default DemoFetchZ;
Run Code Online (Sandbox Code Playgroud)