Search code examples
fetch-apireact-starter-kit

React.js component never refreshed after fetch


Visual Studio React.js starter kit

I don't know why the display component isn't refreshed after fetch is handled? the 'setResults' function is called correctly, and the data is set, but the gallery component never gets the updated data. How do I achieve this? Are the components just set up wrong to start with?

The googleapis book api is searched with 'harry potter' for example. I get back 10 results. But the gallery is never updated with the found data. What do I need to trigger to make the 'gallery' display the newly found data?

I'm guessing that because the fetch.then.then async is in the background, the gallery component isn't somehow notified? I'm in the dark on react and async calls.

main component:

'use strict';

var React = require('react');
var BookGallery = require('./BookGallery.jsx');

var BookSearch = React.createClass({
  getInitialState() {
    return {
      query: '',
      books: []
    };
  },
  setResults(value) {
    this.books = value.items;
    if (this.books) {
      console.log('count of books found: ' + this.books.length);
    } else {
      console.log('nothing found!');
    }
  },
  search() {
    const BASE_URL = 'https://www.googleapis.com/books/v1/volumes?q=';

    if (this.query) {
      console.log("Do the search with " + this.query);

      fetch(BASE_URL + this.query, { method: 'GET' })
        .then(response => response.json())
        .then(json => this.setResults(json));


    } else {
      console.log("Nothing to search for...");

    }
  },

  render() {
    return (

      <div className="Global">
        <h3>Book Search</h3>
        <p>
          <input
              type="search"
              id="inputBookTitle"
              onChange={event => this.query = event.target.value}
              onKeyUp={event => {
                if (event.key == "Enter") {
                  this.search();
                }
              }}
            />
          <span style={{ border: '1px solid garkgrey', padding : '5px', background: 'lightgray' }} >
            <span className="glyphicon glyphicon-search" onClick={() => this.search()} ></span>
          </span>
        </p> 
        <BookGallery list={this.books}/>
      </div>
    );
  }
});

module.exports = BookSearch;

then the gallery component:

'use strict';

var React = require('react');

var BookGallery = React.createClass({
  getInitialState() {
    return {
      books: []
    };
  },
  rate() {

    console.log("Rate the book");
  },
  render() {
    this.books = this.props.list || [];
    console.log(this.books);
    return (
      <div id="bookContainer" >
        <h4>Results:</h4>
        <ul id="gallery">
          {
            this.books.map((item, index) =>
              <li key={index}>{book}</li>
            )
          }
        </ul>
      </div>
    );
  }
});

module.exports = BookGallery;

Solution

  • this.books = value.items;
    

    should be

    this.setState({books: value.items});
    

    React decides when to render the state based upon setState calls, not from just changing the state.

    Also, you seem to be assuming that the state lives on this, it doesn't, it lives on this.state, so wherever you are referring to this.books for rendering, you should be referring to this.state.books.