在渲染反应挂钩之前等待API调用数据

时间:2019-11-20 14:35:29

标签: reactjs react-hooks

我进行API调用。

React似乎在没有数据的情况下继续构建表,因此抛出

错误

Uncaught TypeError: Cannot read property 'map' of undefined

这就是我在做什么

useEffect()非常简单

  const [data, setData] = useState();
  const [isBusy, setBusy] = useState()

  useEffect(() => {
    setBusy(true);
    async function fetchData() {
      const url = `${
        process.env.REACT_APP_API_BASE
        }/api/v1/endpoint/`;

      axios.get(url).then((response: any) => {
        setBusy(false);
        setData(response.data.results)
        console.log(response.data.results);
      });
    }

    fetchData();
  }, [])

然后,我尝试使用上面的API调用中的数据(当它可用时)呈现表

            <div className="col-md-12 mt-5">
              {isBusy ? (
                <Loader />
              ) : (
                  <table className="table table-hover">
                    <thead>
                      <tr>
                        <th scope="col">Pharmacy User Full Name</th>
                        <th scope="col">Tests This Month</th>
                        <th scope="col">Tests This Week</th>
                        <th scope="col">Last Test Date</th>
                      </tr>
                    </thead>
                    <tbody>
                      {data.map((item: any, index: any) => {
                        return (<tr>
                          <th scope="row" key={index}>{item.name}</th>
                          <td>Mark</td>
                          <td>Otto</td>
                          <td>@mdo</td>
                        </tr>
                        )
                      })}

                    </tbody>
                  </table>
                )}
            </div>

以上内容对我来说似乎很直观。所以不确定我需要做什么。谢谢。

3 个答案:

答案 0 :(得分:2)

useEffect仅在组件尝试渲染(太晚)后才将isBusy设置为true。请记住,useEffect仅在浏览器完成绘制后才能运行。因此,isBusy的第一个断言是undefined,其结果为false

true定义为isBusy的初始状态

const [isBusy, setBusy] = useState(true)

或者检查是否存在data而不是isBusy

答案 1 :(得分:2)

您应将isBusy的初始值中的useState设置为true

//                            initial value
const [isBusy, setBusy] = useState(true)

还要在data之前检查data.map

// checking data
{data && data.map((item: any, index: any) => {
    return (<tr>
      <th scope="row" key={index}>{item.name}</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    )
})}

答案 2 :(得分:1)

您的setBusy(true);发生在useEffect内部。 useEffect将在您第一次渲染后执行,所以为时已晚。

我建议通过isBusy的参数将useState默认设置为true:

const [isBusy, setBusy] = useState(true);

然后,您无需在useEffect内将其设置为true。