如何在 ReactJS 中继续之前获取 api

问题描述 投票:0回答:2

我正在尝试使用 Strapi 作为我的 cms 来构建一个超级简单的 React 博客。我遇到了一个问题,它试图在完成获取数据之前渲染数据。我正在尝试显示帖子图像,但我收到有关此处未定义属性的错误:

data.data.attributes.image.data.attributes.formats.large.url

这是ReactJS代码:

import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Navbar from "../components/Navbar";

function Post() {
    const [data, setData] = useState({});
    const { id } = useParams();

    console.log("handle", id);

    const fetchData = () => {
        fetch(`http://localhost:1337/api/posts/${id}?populate=*`)
            .then((response) => {
                return response.json();
            })
            .then((d) => {
                setData(d);
                // console.log(data);
            });
    };

    useEffect(() => {
        fetchData();
    }, []);

    // console.log(data);

    return (
        <>
            <Navbar />
            <img
                src={
                    "http://localhost:1337" +
                    data.data.attributes.image.data.attributes.formats.large.url
                }
                alt="image"
            />
        </>
    );
}

export default Post;

这是检索到的api数据:

{
    "data": {
        "id": 1,
        "attributes": {
            "postTitle": "First Post",
            "datePosted": "2023-04-25",
            "author": "Caleb",
            "postText": "# Hello <u>**_World_**</u>\nThis is my very first blog post!\n\n![flower-right.png](http://localhost:1337/uploads/flower_right_b36ad9cd80.png)\n\n",
            "createdAt": "2023-04-25T07:20:18.295Z",
            "updatedAt": "2023-04-25T08:44:04.003Z",
            "publishedAt": "2023-04-25T07:20:19.972Z",
            "image": {
                "data": {
                    "id": 1,
                    "attributes": {
                        "name": "unsplash_BhfE1IgcsA8-smaller.png",
                        "alternativeText": "header-image",
                        "caption": null,
                        "width": 2560,
                        "height": 1488,
                        "formats": {
                            "thumbnail": {
                                "name": "thumbnail_unsplash_BhfE1IgcsA8-smaller.png",
                                "hash": "thumbnail_unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d",
                                "ext": ".png",
                                "mime": "image/png",
                                "path": null,
                                "width": 245,
                                "height": 142,
                                "size": 57.28,
                                "url": "/uploads/thumbnail_unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d.png"
                            },
                            "small": {
                                "name": "small_unsplash_BhfE1IgcsA8-smaller.png",
                                "hash": "small_unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d",
                                "ext": ".png",
                                "mime": "image/png",
                                "path": null,
                                "width": 500,
                                "height": 291,
                                "size": 222.62,
                                "url": "/uploads/small_unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d.png"
                            },
                            "medium": {
                                "name": "medium_unsplash_BhfE1IgcsA8-smaller.png",
                                "hash": "medium_unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d",
                                "ext": ".png",
                                "mime": "image/png",
                                "path": null,
                                "width": 750,
                                "height": 436,
                                "size": 490.23,
                                "url": "/uploads/medium_unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d.png"
                            },
                            "large": {
                                "name": "large_unsplash_BhfE1IgcsA8-smaller.png",
                                "hash": "large_unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d",
                                "ext": ".png",
                                "mime": "image/png",
                                "path": null,
                                "width": 1000,
                                "height": 581,
                                "size": 884.48,
                                "url": "/uploads/large_unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d.png"
                            }
                        },
                        "hash": "unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d",
                        "ext": ".png",
                        "mime": "image/png",
                        "size": 1276.78,
                        "url": "/uploads/unsplash_Bhf_E1_Igcs_A8_smaller_b163301e2d.png",
                        "previewUrl": null,
                        "provider": "local",
                        "provider_metadata": null,
                        "createdAt": "2023-04-25T06:28:01.746Z",
                        "updatedAt": "2023-04-25T06:35:42.822Z"
                    }
                }
            }
        }
    },
    "meta": {}
}
javascript reactjs strapi
2个回答
1
投票

data
初始化为空对象:

const [data, setData] = useState({});

然后您尝试读取该空对象上的各种嵌套属性:

<img
  src={
    "http://localhost:1337" +
    data.data.attributes.image.data.attributes.formats.large.url
  }
  alt="image"
/>

这显然会失败,因为

{}
没有名为
data
的属性,因此该属性为
undefined
,并且您无法读取
attributes
上的属性
undefined
(或任何属性)。

您也许可以使用可选链接

<img
  src={
    "http://localhost:1337" +
    data.data?.attributes?.image?.data?.attributes?.formats?.large?.url
  }
  alt="image"
/>

但请记住,这可能会在用户界面中显示损坏的图像。 或者,如果您在数据不可用时根本不想显示图像,请在显示图像之前检查数据是否可用:

{ data.data ? <img
  src={
    "http://localhost:1337" +
    data.data?.attributes?.image?.data?.attributes?.formats?.large?.url
  }
  alt="image"
/> : null }

(如果您愿意,您可以将显式的

null
替换为默认图像、加载微调器或什么都不替换。)

您可以通过初始化为

undefined
来稍微简化检查:

const [data, setData] = useState();

然后检查对象本身而不是其属性:

{ data ? <img
  src={
    "http://localhost:1337" +
    data.data?.attributes?.image?.data?.attributes?.formats?.large?.url
  }
  alt="image"
/> : null }

1
投票

您必须在数据显示之前检查数据是否存在,这是一个示例。

return (
   <>
   <Navbar />
 {!data ? ( //if data is currently empty then show the loading (or spinner)
   <p>Loading...</p>
  ) 
  : (
   <img
      src={ "http://localhost:1337" +
            data.data.attributes.image.data.attributes.formats.large.url
           }
          alt="image"
    />
   )
 }
)
© www.soinside.com 2019 - 2024. All rights reserved.