使用 React Hooks 从 YouTube API 获取数据

Fetching data from YouTube API with React Hooks

我正在尝试用我的 YouTube 频道上的播放列表填充一个页面。我正在使用带钩子的 React 16。

import React, { useEffect, useState } from 'react'
import { Container, Row, Col, Card } from 'react-bootstrap'
import PageHeader from '../components/PageHeader'
import axios from "axios"

const Tutorials = () => {
  const [data, setData] = useState({items:[]})
  
  useEffect(() => {
    const fetchData = async () => {
      const results = await axios(
        'https://youtube.googleapis.com/youtube/v3/playlists?part=snippet&channelId=[CHANNEL_ID]&key=[API_EXISTS_AND_TESTED_IN_POSTMAN]'
      );
      setData(results.data.items) 
      console.log(results.data.items);
    }
    fetchData();
  }, [data])

  return (
    <div className="">
      <Container>
        <PageHeader title="Tutorials" />
        <Row xs={1} md={2} className="g-4">
          {data && data.map(item => {
            return(
              <Col xs={12} lg={4}>
                <Card  className="bg-dark">
                  <Card.Img variant="top" src={item.snippet.thumbnails.high.url} />
                  <Card.Body>
                    <Card.Title>{item.snippet.title}</Card.Title>
                    <Card.Text>
                      {item.snippet.description}
                    </Card.Text>
                  </Card.Body>
                </Card>
              </Col>
            )
          })}
        </Row>
      </Container>
    </div>
  )
}

export default Tutorials

这是我得到的。但是,如果我删除 .map() 整个函数并渲染,然后粘贴它并渲染,它将显示。所以连接正在发生。但是我一刷新,我就明白了。是什么赋予了?我想也许数据需要时间来加载,所以我把 setData() 放在 setTimeout 中,并在我尝试渲染数据之前检查数据是否可用,但没有任何效果。邮递员显示我的数据回来了。顺便说一下,YouTube 不提供返回数组。它 returns 一个对象。

我也收到了 403,我不确定它是否相关

尝试用空数组而不是对象来初始化它

const [data, setData] = useState([])

为什么会出现错误

首先使用默认值设置状态:

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

这会将 data 设置为 { items: [] },一个具有名为 items 的 属性 的对象,其值是一个数组。

然后您的组件呈现并运行此行:

data && data.map(item => {

但是{ items: [] }不是数组,所以它没有map方法。这就是错误的来源。

然后在渲染之后更新效果的状态:

setData(results.data.items)

这(可能)将 data 设置为一个数组,其格式与您的状态初始默认值不同。


如何修复错误

您要么想使用数组作为默认值:

const [data, setData] = useState([])

那么你的其他代码应该可以正常工作。

您想在 read/write 您的状态下使用 items 属性。

setData({ items: results.data.items })

还有类似的东西:

data.items.map(item => {

useEffect 钩子依赖项

最后,这将导致无限重新渲染循环:

  useEffect(() => {
    const fetchData = async () => {
      const results = await axios(
        'https://youtube.googleapis.com/youtube/v3/playlists?part=snippet&channelId=[CHANNEL_ID]&key=[API_EXISTS_AND_TESTED_IN_POSTMAN]'
      );
      setData(results.data.items) 
      console.log(results.data.items);
    }
    fetchData();
  }, [data])

data 声明为此效果的依赖项,但此挂钩写入 data。所以这个效果会导致自己重新渲染,无限次。

不过这个效果其实并不依赖于data,所以可以省略。在这种情况下,应使用空数组 [] 作为效果依赖项,效果实际上不使用任何局部变量或状态。

问题是您将状态数据初始化为对象

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

并且当组件进行第一次渲染时,它会尝试映射一个不可能的对象。所以你应该将数据状态初始化为一个数组:

  const [data, setData] = useState([])

此外,{data && ...} 也不是必需的,因为 data 是一个数组,它是一个真值。

代码中的第二个问题与 useEffect 有关,因为您将数据作为依赖项并且在 useEffect 中设置数据,这可能会导致再次调用 useEffect。正确的方法是一个空数组作为第二个参数:

  useEffect(() => {
const fetchData = async () => {
  const results = await axios(
    'https://youtube.googleapis.com/youtube/v3/playlists?part=snippet&channelId=[CHANNEL_ID]&key=[API_EXISTS_AND_TESTED_IN_POSTMAN]'
  );
  setData(results.data.items) 
  console.log(results.data.items);
}
fetchData();
}, [])