繁体   English   中英

反应:当从 API 端点获取数据数组的某些元素时,它们不会被渲染

[英]React: some elements of a data array are not rendered when they are fetched from an API endpoint

当我尝试渲染从 API 端点获取的数据数组时,我遇到了一个奇怪的行为。

例如,它应该渲染 5 个项目,但只渲染了一个项目(数据示例如下)。 当我再次重新获取数据时,问题就解决了。 这个问题很少发生,我找不到任何明确的模式来说明它是如何发生的。

我使用 react 18.2.0 和 axios 从 API 端点获取数据,如下所示:

const getSelectedCandidatesAsync = async () => {
  const url = API_ENDPOINT + "/candidates/of-voter";

  try {
    const response = await axios.get(url);

    if (response.status === 200) {
      return response.data;
    } else {
      return [];
    }
  } catch (err) {
    console.log(err);
  }
};

数据样本:

[
    {
        "id": 11,
        "full_name": "candidate 1",
        "voting_date": "2022-08-11T02:44:49.000Z"
    },
    {
        "id": 10,
        "full_name": "candidate 2",
        "voting_date": "2022-08-11T02:44:49.000Z"
    },
    {
        "id": 1,
        "full_name": "candidate 3",
        "voting_date": "2022-08-11T02:44:49.000Z"
    },
    {
        "id": 30,
        "full_name": "candidate 4",
        "voting_date": "2022-08-11T02:44:49.000Z"
    },
    {
        "id": 3,
        "full_name": "candidate 5",
        "voting_date": "2022-08-11T02:44:49.000Z"
    }
]
import { useContext, useState, useEffect } from "react"
import { UserContext } from '../App';
import { useNavigate } from "react-router-dom";
import dataStore from "../dataStore";

export default function HomePage() {
    const [selectedCandidates, setSelectedCandidates] = useState([]);
    const [isLoading, setIsLoading] = useState(false);
    const [showContent, setShowContent] = useState(false);
    const obj = useContext(UserContext);
    const navigate = useNavigate();
    const { getSelectedCandidatesAsync } = dataStore();

    useEffect(() => {
        if (obj.user === null) {
            navigate("login", { replace: true });
        } else {
            setIsLoading(true);
            getSelectedCandidatesAsync()
                .then((data) => {
                    if (data.length > 0) {
                        setSelectedCandidates(data);
                    }
                    else {
                        navigate('vote', { replace: true })
                    }

                    setShowContent(true)
                    setIsLoading(false)
                })
        }
    }, [])

    return (
        <div className="container">
            {!isLoading && showContent &&
                <>
                    <div className="row mt-4 align-items-center justify-content-center">
                        <div className="col-md-4 text-center">
                            <h2>Thank you for voting!</h2>
                        </div>
                    </div>

                    <div className="row mt-4 align-items-center justify-content-center">
                        <div className="col-md-6 alert alert-success" role="alert">
                            <div style={{ fontSize: '1.2rem' }} className="mt-4">You have selected <strong>{selectedCandidates.length}</strong> candidate(s):</div>
                            <ul style={{ fontSize: '1.2rem' }}>
                                {selectedCandidates.map(item => <li key={item.id}>{item.full_name}</li>)}
                            </ul>
                        </div>
                    </div>
                </>
            }

            {isLoading &&
                <div style={{ height: '90vh' }} className="row align-items-center justify-content-center">
                    <div className="col-md-4 text-center">
                        <div className="spinner-border" role="status">
                            <span className="visually-hidden">Loading...</span>
                        </div>
                    </div>
                </div>
            }

        </div>
    )
}

检查if (response.status === 200)可能是不必要的,并且可能是您问题的根源。

如果请求不成功,Axios 将抛出异常,因此无需检查。 如果响应是缓存的HTTP 304 Not Modified ,则不应省略数据。

最后,不要在不保持 promise 拒绝链继续运行的情况下,在可消耗的异步 function 中捕获错误/ promise 拒绝。 不这样做意味着您的消费者会看到已解析的 promise 带有undefined的数据。

const getSelectedCandidatesAsync = async () => {
  const { data } = await axios.get(`${API_ENDPOINT}/candidates/of-voter`);

  // parsing dates will be helpful
  return data.map(({ voting_date, ...candidate }) => ({
    ...candidate,
    voting_date: new Date(voting_date),
  }));
};

这是一个示例组件

const Candidates = () => {
  const navigate = useNavigate();

  const [selectedCandidates, setSelectedCandidates] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    if (obj.user === null) {
      navigate("login", { replace: true });
    } else {
      setIsLoading(true);

      getSelectedCandidatesAsync()
        .then((data) => {
          if (data.length > 0) {
            setSelectedCandidates(data);
          } else {
            navigate("vote", { replace: true });
          }
        })
        .catch(console.error)
        .finally(() => {
          setIsLoading(false);
        });
    }
  }, []);

  if (isLoading) {
    return <p>Loading...</p>;
  }

  return selectedCandidates.map(({ id, full_name, voting_date }) => (
    <div key={id}>
      <p>{full_name}</p>
      <p>{voting_data.toLocaleDateString()}</p>
    </div>
  ));
};

暂无
暂无

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

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