Call class method within a promise returns: Uncaught (in promise) TypeError: _this3.updateShelvesState is not a function

1

Good afternoon!

I created a method called updateShelvesState which is called before the component is rendered, and the onChange of another component called Book .

This method takes an array and creates a new array organized by the key shelf of each object that exists inside the array.

When rendering the page, when I call the method inside componentDidMount , everything happens well.

However when using the same method within a promise, onChange  of the Book subcomponent, I get the following error:

Uncaught (in promise) TypeError: _this3.updateShelvesState is not a function

The getAll function only returns the API data.

Follow the code below:

import React, { Component } from "react";
import "./../App.css";
import { Link } from "react-router-dom";
import { getAll, update } from "../BooksAPI";
import Book from "./../components/Book";

class BookContainer extends Component {
  state = {
    shelves: []
  }

  componentDidMount() {
    getAll()
      .then(books => this.updateShelvesState(books))
      .catch(error => console.log(error));
  }

  updateShelvesState(books) {
    const booksGroupByShelf = books.reduce((newObj, book) => {
      newObj[book.shelf] = newObj[book.shelf] || [];
      newObj[book.shelf].push(book);
      return newObj;
    }, {})

    const shelves = Object.keys(booksGroupByShelf).map(key => {
      return { group: key, items: booksGroupByShelf[key] };
    });
    this.setState({ shelves });

  }


  onChangeShelf(book, shelf) {
    update(book, shelf)
     .then(getAll)
     .then(data => this.updateShelvesState(data) )    
  }

  render() {
    const { shelves } = this.state;

    return (
      <div className="app">
        <div className="list-books">
          <div className="list-books-title">
            <h1>MyReads</h1>
          </div>
          <div className="list-books-content">
            <div>
              {shelves.map((shelf, index) => {
                return (
                  <div key={index} className="bookshelf">
                    <h2 className="bookshelf-title">{shelf.group}</h2>
                    <div className="bookshelf-books">
                      {shelf.items.length > 0 && (
                        <ol className="books-grid">
                          {shelf.items.map(item => (
                            <Book
                              key={item.id}
                              book={item}
                              onChangeShelf={this.onChangeShelf}
                            />
                          ))}
                        </ol>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
          <div className="open-search">
            <Link to="/search">Add a book</Link>
          </div>
        </div>
      </div>
    );
  }
}

export default BookContainer;

Thank you very much for your attention.

    
asked by anonymous 08.11.2017 / 19:39

1 answer

1

You have to bind to the class you are in, for the method to run in the correct / this context.

Mute

onChangeShelf={this.onChangeShelf}

for

onChangeShelf={this.onChangeShelf.bind(this)}
    
08.11.2017 / 19:55