【问题标题】:How to build up an object with API calls in componentDidMount to set state如何在 componentDidMount 中使用 API 调用构建对象以设置状态
【发布时间】:2020-03-29 15:29:48
【问题描述】:

我在 React 中使用 Spotify API 闲逛,并且在为嵌套数据进行 api 调用时遇到了麻烦。我在 componentDidMount 中的计划是:

  1. 获取用户帐户数据
  2. 使用该帐户数据获取用户的播放列表
  3. 使用这些播放列表获取每个播放列表中的曲目
  4. 建立一个包含名称、ID 和曲目的播放列表对象
  5. 将播放列表对象推送到播放列表数组
  6. 使用用户帐户数据和播放列表数组设置状态

这是我的 componentDidMount 和获取播放列表曲目的方法:

    async componentDidMount() {
        const userResponse = await axios.get(`https://api.spotify.com/v1/me`, {
            headers: {
                Authorization: 'Bearer ' + this.state.access_token
            }
        });

        const playlistsResponse = await axios.get(
            `https://api.spotify.com/v1/users/${userResponse.data.id}/playlists`,
            {
                headers: {
                    Authorization: 'Bearer ' + this.state.access_token
                }
            }
        );


        let playlists = [];
        playlistsResponse.data.items.map((playlist) => {
      const tracks = this.getTracks(playlist.id);
            let newPlaylist = {
                name: playlist.name,
                id: playlist.id,
                tracks: tracks
            };
            playlists.push(newPlaylist);
        });

        this.setState({
            playlists: playlists,
            userData: userResponse.data
        });
    }

    async getTracks(playlistID) {
        const tracks = await 
axios.get(`https://api.spotify.com/v1/playlists/${playlistID}/tracks`, {
            headers: {
                Authorization: 'Bearer ' + this.state.access_token
            }
        });
        return tracks;
    }

在渲染中控制台记录状态后,我看到我能够将 userData 设置为状态。我也可以设置播放列表,但是,只有 name 和 id 被传递,并且曲目被设置为 Promises。我是否在尝试在地图内调用曲目 API 以便一次构建播放列表对象 1 个?

更新:

所以我通过将我的地图回调分配为异步函数来让它工作。这是sn-p:

        let playlists = [];

        playlistsResponse.data.items.map(async (playlist) => {
            const tracksResponse = await axios.get(`https://api.spotify.com/v1/playlists/${playlist.id}/tracks`, {
                headers: {
                    Authorization: 'Bearer ' + this.state.access_token
                }
            });

            let newPlaylist = {
                name: playlist.name,
                id: playlist.id,
                tracks: tracksResponse
            };
            playlists.push(newPlaylist);
        });

        this.setState({
            playlists: playlists,
            userData: userResponse.data
        });
    }

这是一种公平的处理方式吗?对我来说,我在地图的每次迭代中等待 trackResponse 数据,然后在稍后构建我的播放列表对象时使用它是有道理的。将我的地图回调包装在 async/await 中是否安全/常见做法?

更新 2:

好吧,也许它不起作用。当我检查 Chrome devtools 时,我可以看到所有状态,但是当我尝试渲染状态时,什么都不会吐出。

【问题讨论】:

  • setState 本质上是异步的。您需要等待tracks 被获取,然后才能执行setState
  • 但是我如何等待曲目被获取?我想,因为我将 getTracks 设为异步函数,所以每次在我的地图中调用它时,它都会等待获取轨道,然后再返回它们。
  • 你需要改变函数的顺序。最后移动setState。还存储 tracks 的响应,就像您对播放列表和 userReposne 所做的那样。会更容易阅读。像这样:const tracksResponse = await getTracks
  • setState 是 componentDidMount 内部的最后一个,getTracks 是我在 componentDidMount 外部定义的方法
  • 我认为你误解了异步等待。例如,在您的函数getTracks 中,async await 将用于在解析完成后返回。它不能用作回调

标签: reactjs async-await axios


【解决方案1】:

在解析地图之前,您可能是 setState。我建议你使用Promise.all,像这样:

let playlists = [];
    const map = playlistsResponse.data.items.map((playlist) => {
  const tracks = this.getTracks(playlist.id);
        let newPlaylist = {
            name: playlist.name,
            id: playlist.id,
            tracks: tracks
        };
        playlists.push(newPlaylist);
    });

   await Promise.all(map);

    this.setState({
        playlists: playlists,
        userData: userResponse.data
    });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-21
    • 2020-03-06
    • 1970-01-01
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多