mandok
mandok

Reputation: 492

Unable to display result of spotify api query in a FlatList

I'm working on a very simple react-native app where I type the name of an artist in a search bar and display a Flatlist of artists that I got using the spotify api.

I have 2 files my App.js that does the rendering and fetcher.js that implements the api calls.

But I'm unable to get the list to appear, I'm unable to set the state of artists.

App.js

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  FlatList,
  StatusBar,
  TextInput,
} from 'react-native';

import colors from './utils/colors';
import { List, ListItem, SearchBar } from 'react-native-elements';
import { searchArtist } from './utils/fetcher';
import { debounce } from 'lodash';


export default class spotilist extends Component {
  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      data: [],
      query: '',
      artists: [],
      error: null,
      refreshing: false,
    };
  }


  render() {
    return (
      <View style={ styles.container }>
        <StatusBar barStyle="light-content" />
        <TextInput style={ styles.searchBox }
          value={this.state.value}
          onChangeText={ this.makeQuery }
        />
        <Text> {this.state.artists}  </Text>
      </View>
    );
  }

  makeQuery = debounce(query => {
    searchArtist(query)
      .then((artists) => {
        this.setState({
          artists: this.state.artists,
        });
        //console.log(artists)
      })
      .catch((error) => {
        throw error;
      });
  }, 400);

}


const styles = StyleSheet.create({
  container: {
    paddingTop: 64,
    flex: 1,
    backgroundColor: colors.white,
  },
  searchBox: {
    height: 40,
    borderColor: colors.black,
    borderWidth: 2,
    margin: 16,
    paddingLeft: 10,
    fontWeight: '800',
  },
  row: {
    flex: 1,
    margin: 30,
    alignSelf: 'stretch',
    justifyContent: 'center',
  },
});

fetch.js

export function searchArtist(query) {

  const ClientOAuth2 = require('client-oauth2')

  console.log("Query : " + query)

  const spotifyAuth = new ClientOAuth2({
    clientId: CLIENT_ID,
    clientSecret: CLIENT_SECRET,
    accessTokenUri: 'https://accounts.spotify.com/api/token',
    authorizationUri: 'https://accounts.spotify.com/authorize',
    scopes: []
  })

  spotifyAuth.credentials.getToken()
    .then((user) => user.accessToken)
    .then((token) => getQuery(token, query))
    .then((result) => {
      console.log(result) // No list :(
      return result
    });
}

function getQuery(token, query) {

  console.log("Query2 : " + query)

  const settings = {
    "url": `https://api.spotify.com/v1/search?q=${ query }&type=artist`,
    "method": "GET",
    "headers": {
      "authorization": "Bearer " + token,
      "cache-control": "no-cache",
    }
  }

  fetch(settings)
    .then((res) => res.json())
    .then(data => {
      const artists = data.artists ? data.artists.items : [];
      console.log(artists)  // I get the list in the debbuger
      return artists;
    });
}

Thank you for your help.

Upvotes: 0

Views: 169

Answers (2)

Andrii Skrebets
Andrii Skrebets

Reputation: 254

You just need to return you fetch promise in getQuery

function getQuery(token, query) {

  console.log("Query2 : " + query)

  const settings = {
    "url": `https://api.spotify.com/v1/search?q=${ query }&type=artist`,
    "method": "GET",
    "headers": {
      "authorization": "Bearer " + token,
      "cache-control": "no-cache",
    }
  }

  return fetch(settings)
    .then((res) => res.json());
}

And then when you call

spotifyAuth.credentials.getToken()
    .then((user) => user.accessToken)
    .then((token) => getQuery(token, query))
    .then((result) => {
      console.log(result) // No list :(
      return result
    });

getQuery will return this promise and you can handle it like you did before in getQuery:

return spotifyAuth.credentials.getToken()
    .then((user) => user.accessToken)
    .then((token) => getQuery(token, query))
    .then(data => {
      return data.artists ? data.artists.items : [];
    });

then you can simple return this promise and handle wherever you want

Upvotes: 2

MisterSnow
MisterSnow

Reputation: 86

You need to map through the array of artists. All react and react-native components cannot render data outside of data primitives (such as strings and numbers).

Such as:

{
  this.state.artists.map(artist => {
    return (
      <Text key={artist.id}>{artist.name}</Text>
    )
  })
}

If the elements inside the state.artists array are just strings, just return the artist inside the text element.

The key value is for React to quickly assimilate the virtual dom to dom amidst state changes.

Upvotes: 1

Related Questions