使用 UseEffect 和 UseState 在功能组件中做出反应的承诺不起作用
我在使用 useEffect 和 useState 在功能组件中获取数据并将它们设置为状态时遇到了问题。
我的问题是,我想将使用 axios async/await 完成的数据获取保存在单独的文件中,以提高应用程序的可扩展性,但是我不明白如何在承诺得到解决(而不是被拒绝)的情况下更新状态。
特别是,我试图从承诺中检索一个名为状态数据的表行数组,但我不知道如何在状态中设置响应的结果
这是组件文件中的代码:
const [data, setData] = React.useState([]);
useEffect(() => {
const { id } = props.match.params;
props.getTableRows(id).then((res) => {
setData(res);
});
//or is it better:
//props.getTableRows(id).then(setData); ?
}, []);
和我的 action.js:
export const getTableRows = (id, history) => async (dispatch) => {
try {
const res = await axios.get(`/api/test/${id}`);
dispatch({
type: GET_TEST,
payload: res.data.rows,
});
} catch (error) {
history.push("/test");
}
};
在上图中,可以看到在 action.js 中调用的 promise 响应内的 rows 数组是存在的。
不幸的是,此代码不起作用,错误: Uncaught (in promise) TypeError: Cannot read property 'forEach' of undefined
我找到了另一个解决方案,即在 useEffect 方法中定义 promise,如下所示:
useEffect(() => {
const { id } = props.match.params;
const fetchData = async () => {
const result = await axios.get(`/api/test/${id}`);
setData(result.data.rows);
};
fetchData();
}, []);
此代码在我的应用程序中有效,但正如我所说,我不喜欢在组件文件中拥有 promise,我希望将它们全部放在 action.js 中以实现应用程序的可扩展性(如果 url 发生变化,我不必更改所有文件),但在这种情况下,我不知道将 setData(result.data.rows); 放在哪里,这似乎是最后一个例子中的正确选择
任何有什么建议吗? 谢谢
您仍然需要使用 async/await。.then() 在返回值时执行,但是您的函数将继续渲染并且不会等待它。(尝试在空状态下访问 forEach 会导致它出错)。出错后,通过 .then() 做出的承诺将更新值,这就是您可以在控制台中看到它们的原因。
useEffect(() => {
async function getData() {
const { id } = props.match.params;
await props.getTableRows(id).then((res) => {
setData(res);
});
}
getData()
}, []);
此外,在访问状态之前,您可以检查是否为空值(一般来说,这是一种良好做法)。
if (this.state.somestate != null) {
//Run code using this.state.somestate
}
我没有看到您从
getTableRows
返回任何内容。您只是分派了结果,但没有返回函数调用的
res
。
如果您提供错误跟踪,将会很有帮助。