2

I've got the last.fm API working in my app, I'm grabbing related artists. So the idea is you search for an artist and it returns a list of related artists.

If I use 'onClick' it works perfect because it grabs the input value, but I want to use 'onChange' and it seems to returning the wrong results. I think it's because it's undefined at some stages or something!

Any ideas how to fix this?

// AJAX

import axios from "axios";

module.exports = {
  fetchArtistCategory: (artist) => {
    let key = "12345";
    let encodedURI = window.encodeURI('http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&artist=' + artist + '&api_key=' + key + '&format=json');
    return axios.get(encodedURI)
    .then((res) => {
      return res
    });
  }
}

// App

import React from "react";
import {render} from "react-dom";
import Artists from "./components/Artists.js";
import Api from "./components/Api.js";

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      artist: [],
    }

    this.searchArtist = this.searchArtist.bind(this);
  }
  componentDidMount() {

  }
  searchArtist() {
    Api.fetchArtistCategory(this.searchArtists.value)
    .then((res) => {
      this.setState({
        artist: res.data.similarartists.artist
      });
    })
  }
  render() {
    return (
      <div>
        <Artists artistValue={this.state.artist} />
        <input type="text" placeholder="Search artist" ref={(ref) => this.searchArtists = ref} onChange={this.searchArtist} />
        <input type="submit"/>
      </div>
    )
  }
}

render(<App />, document.getElementById("main"));
1
  • Whats the output of console.log(this.searchArtists) inside this.searchArtist method? Commented Jun 14, 2017 at 21:15

2 Answers 2

2

It's hard to diagnose your problem without knowing what you mean by "returning the wrong results". My initial guess is that you're thinking about onChange incorrectly.

onchange fires for every single text change. If I typed in "Bob Dylan" into your text field, onChange would fire once for each change as I type (eg. "B", "Bo", "Bob", "Bobe", "Bob"(delete e), "Bob "...). Thus you'll be firing a lot of API requests. This is fine for autocomplete, but requires rate-limiting, smart response ordering, etc., and is a different use case than yours.

It sounds like you only want to fire one API request once the user has completed their thought. To do this, you should try the onfocusout or onblur attributes -- as their names imply, they will fire when the user has completed their input and left the text field.

Sign up to request clarification or add additional context in comments.

3 Comments

Hi, your explanation is correct that's exactly what I'm looking to do. My confusion is if it's requesting the API every letter than why wouldn't it grab the correct results after the final letter of the artist has been typed? FWIW onBlur does work when you click outside but you can definitely do it whilst inside the input as I've seen examples of it.
Assuming that people type about 5 characters a second, you're sending 5 api requests per second. Each request takes an unpredictable amount of time to respond, and some APIs limit the number of requests you can make per second. So, you have a stream of unordered responses coming back and you can't assume that your most recent request corresponds to the most recent response. RxJS is a nice tool for handling this -- and look up rate-limiting.
Yeah that all makes sense, there's a video by Stephen Grider where he used the youtube API search and uses onchange as I wanted to so I'm not too sure. Maybe that's quicker to respond! Thanks for the help.
-1

shouldn't you be passing an event through with the onChange handler?

searchArtist(event) {
    Api.fetchArtistCategory(event.target.value)
    .then((res) => {
      this.setState({
        artist: res.data.similarartists.artist
      });
    })
  }

^ The only piece of code you should need to change if everything else if correct

And you need the ref unless I'm misunderstanding. You get the value of the input field as event.target.value inside of the event handler.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.