以下代码完美运行:
import { useState, useEffect } from 'react';
const Main = () => {
const [ form, setForm ] = useState({
error: {},
data: {}
});
useEffect( () => {
async function fetchData() {
const promise = await fetch(`test.json`);
const result = await promise.json();
const newForm = {...form};
newForm.data = result;
setForm(newForm);
console.log('executed');
}
fetchData();
}, []); // *** I will speak to this [] second argument shortly in question below
return (
<div>
<p>{Object.keys(form.data).length}</p>
</div>
);
};
它所做的只是在组件安装上,获取一个包含 test.json
内容的 {"data":"hello"}
文件。这完美地工作并且做我想要的。
但是,在我的控制台中,我看到编译器抱怨此消息 Line 20:6: React Hook useEffect has a missing dependency: 'form'. Either include it or remove the dependency array react-hooks/exhaustive-deps
。当我添加 [ form ]
作为 useEffect
的第二个参数时,或者如果我从 []
中删除 useEffect
第二个参数,那么 useEffect
会进入无限循环。< /p>
为什么我的编译器会警告我出现问题并建议导致无限循环的操作?
答案 0 :(得分:1)
此错误/警告是由您的 linter 造成的。
linter 规则假定您遗漏了依赖项数组中 useEffect
外部的变量,这会导致意外结果。
您可以禁用 lint 规则:
useEffect(() => {
}, []); // eslint-disable-line react-hooks/exhaustive-deps
/* eslint-disable react-hooks/exhaustive-deps */
useEffect(() => {
}, []);
如果您不想禁用规则,您可以切换到使用 setState
回调语法,该语法提供当前状态作为参数。
import { useState, useEffect } from 'react';
const Main = () => {
const [ form, setForm ] = useState({
error: {},
data: {}
});
useEffect( () => {
async function fetchData() {
const promise = await fetch(`test.json`);
const result = await promise.json();
setForm(currentForm => {
const newForm = {...currentForm};
newForm.data = result;
return newForm;
});
console.log('executed');
}
fetchData();
}, []);
return (
<div>
<p>{Object.keys(form.data).length}</p>
</div>
);
};
这消除了在 useEffect 中包含 form
的需要。
至于 linter 可能认为这是一个问题的原因,请看以下示例:
export default function App() {
const [data, setData] = useState({ a: 'Initial Value', b: null });
const [control, setControl] = useState({ a: "Initial Value", b: null });
useEffect(() => {
const asyncFunc = () => {
new Promise(resolve => {
setTimeout(() => resolve(true), 2000)
})
.then(() => {
// The value of "data" will be the initial value from
// when the useEffect first ran.
setData({...data, b: 'Async Updated'});
// The value of "current" wille be the current value of
// the "control" state.
setControl(current => ({ ...current, b: "Async Updated" }));
})
};
asyncFunc();
// Update the data state while the async function has not
// yet been completed.
setData({ a: 'Changed Value', b: null });
// Update the control state while the async function has not
// yet been completed.
setControl({ a: "Changed Value", b: null });
}, []);
// The data value will swap to "Changed Value" and then back
// to "Initial Value" (unexpected) once the async request is
// complete.
// As the control used the current value provided by the
// callback it is able to avoid this issue.
return (
<div>
Data:
<pre>{JSON.stringify(data, null, "\t")}</pre>
Control:
<pre>{JSON.stringify(control, null, "\t")}</pre>
</div>
);
};
您可以在此处运行此示例:https://stackblitz.com/edit/react-hmfddo