我正在尝试学习 React 钩子。我正在创建一个利用 NY Times api 的简单新闻应用。
当我将依赖项留空时,不会加载任何内容,而当我将数据用作依赖项时,它会进入无限循环。
当我使用 isLoading 时,它可以工作,但随后我收到错误“localhost/:1 Unchecked runtime.lastError:消息端口在收到响应之前关闭。”和“localhost/:1 错误处理响应:TypeError:无法读取未定义的属性‘级别’”
main.js
import React, { useEffect, useState } from "react";
import { nyTimesApi } from "../services/Api";
const Main = () => {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState([]);
const fetchData = async () => {
const result = await nyTimesApi();
setData(result);
setIsLoading(false);
console.log(data.results);
};
useEffect(() => {
fetchData();
}, [isLoading]);
return <div className="main">work</div>;
};
export default Main;
我也收到警告,当使用 isLoading 时,在终端中说“React Hook useEffect 缺少依赖项:'fetchData'。要么包含它,要么删除依赖项数组 react-hooks/exhaustive-deps”
我做错了什么?
答案 0 :(得分:1)
useEffect
的第二个参数是一个变量数组,每次改变时都会触发 useEffect 中的函数被调用。
您将 [isLoading]
作为 useEffect 的第二个参数,并在 fetchData()
内更新 this 的值。这将导致 useEffect 触发器一次又一次地发生。
如果你只想让 useEffect 调用一次(类似于基于类的组件中的 ComponentDidMount),那么你需要指定一个空数组作为第二个参数。
useEffect(() => {
fetchData();
}, []);
答案 1 :(得分:0)
无限循环是由 setData(result)
和 [data]
组合使用引起的:
useEffect
。setData(result)
将异步更新 data
值并触发重新渲染。useEffect
将再次运行,因为 data
将无法成功完成引用比较。警告“React Hook useEffect has a missing dependency”在一定程度上是不言自明的。
使用未包含在依赖项数组中的外部(useEffect
)变量可能意味着该变量的值会发生变化并且不会重新触发 useEffect
或该值可能不是预期值。
以下是如何修复原始代码段的示例:
import React, { useEffect, useState } from "react";
import { nyTimesApi } from "../services/Api";
const Main = () => {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState([]);
useEffect(() => {
// Create function inside useEffect so that the function is only
// created everytime the useEffect runs and not every render.
const fetchData = async () => {
const result = await nyTimesApi();
setData(result);
setIsLoading(false);
// setData will update state asynchronously.
// Log the value stored instead.
console.log(result.results);
};
//Run data fetching function.
fetchData();
},
// Both of these are set functions created by useState and will
// not change for the life of the component, but adding them to
// the dependency array will make your linter happy.
// Do not need to check isLoading as it is always true on component
// mount.
[setData, setIsLoading]);
return <div className="main">work</div>;
};
export default Main;