繁体   English   中英

在 React 中渲染之前等待 function 完成或加载数据的正确方法?

[英]Proper way to wait for a function to finish or data to load before rendering in React?

我有以下反应代码,它从 api 中提取一些数据并输出它。 result['track_list']中,我收到带有时间戳的曲目列表,在aggTrackList()中,我根据日/月/年将数据聚合到键值对中,然后在我创建的 Card 组件中显示聚合数据。

import React, { useState, useEffect } from "react";

function App() {
  const [error, setError] = useState(null);
  const [isLoaded, setIsLoaded] = useState(false);
  const [trackList, settracks] = useState([]);
  const [sortby, setSortby] = useState("day");
  const [sortedList, setSortedList] = useState([]);

  useEffect(() => {
    aggTrackList();
  }, [sortby]);
  
  const aggTrackList = () => {
    setSortedList([]);
    let sortedObj = {};
    switch (sortby) {
      case "day":
        trackList.forEach((track) => {
          let dayVal = new Date(track[3]).toDateString();
          dayVal in sortedObj
            ? sortedObj[dayVal].push(track)
            : (sortedObj[dayVal] = [track]);
        });
        setSortedList(sortedObj);
        break;
      case "month":
        trackList.forEach((track) => {
          let monthVal = new Date(track[3]).toDateString().split(" ");
          let monthYear = monthVal[1] + monthVal[3];
          monthYear in sortedObj
            ? sortedObj[monthYear].push(track)
            : (sortedObj[monthYear] = [track]);
        });
        setSortedList(sortedObj);
        break;
      case "year":
        trackList.forEach((track) => {
          let yearVal = new Date(track[3]).toDateString().split(" ");
          let year = yearVal[3];
          year in sortedObj
            ? sortedObj[year].push(track)
            : (sortedObj[year] = [track]);
        });
        setSortedList(sortedObj);
        break;
    }
  };

  const getUserTracks = (username) => {
    fetch(`http://localhost/my/api/${username}`, {
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
      },
    })
      .then((res) => res.json())
      .then(
        (result) => {
          settracks(result["tracks_played"]);
          aggTrackList();
          setIsLoaded(true);
        },
        (error) => {
          console.log(error);
          setIsLoaded(true);
          setError(error);
        }
      );
  };

  return (
    <div className="App">
      <SortMenu
        setSort={(selected) => {
          setSortby(selected);
        }}
      />
      <UserForm onSubmit={getUserTracks} />
      <div className="trackList">
        {isLoaded ? (
          Object.entries(sortedList).map(([day, track]) => (
            <Card
              className="card"
              displayMode={sortby}
              key={day}
              timestamp={day}
              content={track}
            />
          ))
        ) : (
          <div>...</div>
        )}
      </div>
    </div>
  );
}
export default App;

我遇到的问题是提交UserForm并接收数据时。 除非我在加载数据后单击排序菜单选项之一来更新sortby state,否则卡片元素不会呈现。 如何让数据在加载后自动显示?

我正在创建这个项目来学习 React,所以如果有什么可以做得更好或者我做错了什么,请告诉我。

谢谢。

编辑:我在代码框上的代码 - https://codesandbox.io/s/fervent-minsky-bjko8?file=/src/App.js带有来自我的 API 的示例数据。

您可以通过两种方式做到这一点:

  1. 以阻塞方式使用useLayoutEffect钩子。 参考 这个
  2. 以非阻塞方式使用useEffect钩子。 参考这个

1. useLayoutEffect

这里需要注意的是,首先执行钩子传递的function,然后渲染组件。

  1. useLayoutEffect中进行 API 调用,然后在从 API 获得响应后设置数据。 数据最初可以在哪里
const [data, setData] = useState(null)

JSX 必须适当地处理来自服务器的不同响应的所有情况。

2. useEffect

这里要注意的是,这个 function 在组件渲染之后运行。

  1. useEffect挂钩中进行 API 调用。 获得数据后,相应地设置 state 变量。

在这里,您的 jsx 可能类似于

{
    data === null ? (
     <Loader />
       ) : data.length > 0 ? (
          <Table data={data} />
       ) : (
          <NoDataPlaceholder />
       )
}

在这里,我假设数据是对象列表。 但适当的条件可以用于任何其他格式。 在这里,当使用 useEffect 中的useEffect调用获取数据时,用户将看到加载 animation。 获取数据后,将向用户显示数据。 如果数据为空,将向用户显示适当的占位符消息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM