开发者问题收集

使用 UseEffect 和 UseState 在功能组件中做出反应的承诺不起作用

2020-08-14
6157

我在使用 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); 放在哪里,这似乎是最后一个例子中的正确选择

任何有什么建议吗? 谢谢

2个回答

您仍然需要使用 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
}
Greg M
2020-08-14

我没有看到您从 getTableRows 返回任何内容。您只是分派了结果,但没有返回函数调用的 res 。 如果您提供错误跟踪,将会很有帮助。

xi.lin
2020-11-27