UseEffect 被多次调用
Posted
技术标签:
【中文标题】UseEffect 被多次调用【英文标题】:UseEffect being called multiple times 【发布时间】:2020-10-19 04:46:18 【问题描述】:我以为useEffect
只在渲染后调用一次,但它被执行了多次,而且不是按照我预期的顺序。
我希望它在提取过程中发送消息“数据加载”,然后在提取完成后,呈现标题字段并警告“..Done...”一次,这应该是结束。
我在两个点添加了 ALERT 和控制台日志以确定流程,并且警报和控制台日志都以不同的顺序出现不止一次。您能否运行此代码并查看行为。我将第二个参数数组保留为 null 以使其仅运行一次但没有帮助。
请澄清反应 RENDER 是否意味着在屏幕上显示? 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;
【问题讨论】:
【参考方案1】:您的useEffect
在每个渲染周期只执行一次,但您的useEffect
中有几个状态更新会导致重新渲染。因此,您会收到很多警报。
See a demo of your code 并查看 console.logs 以及 cmets
还要注意useEffect 会
当你提供空数组依赖时,你的 useEffect 执行一次 当您将某个值作为依赖项(例如:[name]
)时,您的 useEffect 在名称状态/属性更改时执行
如果不传递依赖数组,则每次重新渲染时都会执行 useEffect。
Read here on re-render
【讨论】:
【参考方案2】:像这样重构它。
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;
【讨论】:
看起来好多了。我要试试。一个问题。为什么不将函数 fetchData 作为异步等待? const fetchData = () => setLoading(true); fetch("jsonplaceholder.typicode.com/todos/1") .then((response) => response.json()) .. .then 就像 async-await 一样工作,对 DX 来说更好。在上面的代码中,您告诉编译器在响应为 200 时仅设置数据,否则设置错误。但在您的代码中,您不处理错误。 @SerajVahdati 我正在学习 react.js 并且遇到了类似的问题。我从这个答案中了解到,todo
和loading
等状态对象如果作为依赖项传递,则不应在useEffect
方法内更新,否则useEffect
将被一次又一次地调用。就我而言,我从 API 获取数据并将其显示在同一页面上。通过应用此答案中提到的代码修复,我有一个警告:“React Hook useEffect 缺少依赖项:'fetchData'。要么包含它,要么删除依赖项数组。”
@Junaid 这只是一个警告,并不重要。这段代码没有任何问题。但如果你想修复它。您可以在useEffect
中声明您的fetchData
函数并在声明后立即调用它。它必须为你解决
一个小改进。如果您最终将依赖项放在useEffect
中,请检查您是否已经在 fetchData() 中拥有数据并返回而不是再次调用服务器,这将阻止您在不需要时向服务器发送相同的请求。 fetchData() if ( data ) return; setLoading(true);....
以上是关于UseEffect 被多次调用的主要内容,如果未能解决你的问题,请参考以下文章
ReactJs/NextJs useEffect() 总是被调用两次