反应应用状态不更新

时间:2018-05-03 12:30:02

标签: reactjs jsx

我正在创建一个基本的React应用程序来存放某些书架上的书籍,并且我正在尝试创建在书架之间移动书籍的功能。

我遇到的问题是,当我从图书对象下拉列表中选择新目标广告架时,onUpdateShelf中的ListBooks.js方法似乎无法启动更新和后续状态更改。

我是React的新手,我的理解是调用setState中的updateShelf函数应该触发使用更新的对象重新渲染。

我的问题是,我的实施是错误的,在哪里?

App.js

import React, { Component } from 'react'
import ListBooks from './ListBooks'
import * as BooksAPI from './utils/BooksAPI'
import { Route } from 'react-router-dom'

class BooksApp extends Component {
  state = {
    books: []
  }

  componentDidMount() {
    BooksAPI.getAll()
    .then((books) => {
      this.setState(() => ({
        books
      }))
    })
  }

  updateShelf = (book, shelf) => {
    console.log(book)
    console.log(shelf)
    this.books.forEach(b => {
      if(b.id === book.id && b.shelf !== book.shelf ) {
        b.shelf = shelf
        this.setState((currentState) => ({
          books: currentState.books
        }))
      }
    });

    BooksAPI.update(book, shelf)
  }

  render() {
    return (
      <div>
        <Route exact path='/' render={() => (
          <ListBooks
          books={this.state.books}
          onUpdateShelf={this.updateShelf}
          />
        )} />
      </div>
    )
  }
}
export default BooksApp

我的ListBooks.js

import React, { Component } from 'react';
import PropTypes from 'prop-types'
import './App.css'

const shelves = [
  {
    key: 'currentlyReading',
    name: 'Currently Reading'
  },
  {
    key: 'wantToRead',
    name: 'Want To Read'
  },
  {
    key: 'read',
    name: 'Read'
  }
];

class ListBooks extends Component {

    static propTypes = {
       books: PropTypes.array.isRequired
    }

    state = {
        showSearchPage: false,
        query: ''
      }

    render() {

        const { books, onUpdateShelf } = this.props

        function getBooksForShelf(shelfKey) {
          return books.filter(book => book.shelf === shelfKey);
        }

        console.log(books);

        return(
            <div className="app">
            {this.state.showSearchPage ? (
              <div className="search-books">
                <div className="search-books-bar">
                  <a className="close-search" onClick={() => this.setState({ showSearchPage: false })}>Close</a>
                  <div className="search-books-input-wrapper">
                    {/*
                      NOTES: The search from BooksAPI is limited to a particular set of search terms.
                      You can find these search terms here:
                      https://github.com/udacity/reactnd-project-myreads-starter/blob/master/SEARCH_TERMS.md
                      However, remember that the BooksAPI.search method DOES search by title or author. So, don't worry if
                      you don't find a specific author or title. Every search is limited by search terms.
                    */}
                    <input type="text" placeholder="Search by title or author"/>
                  </div>
                </div>
                <div className="search-books-results">
                  <ol className="books-grid"></ol>
                </div>
              </div>
            ) : (
              <div className="list-books">
                <div className="list-books-title">
                  <h1>My Reads</h1>
                </div>
                <div className="list-books-content">
                  <div>
                    { shelves.map((shelf) => (
                      <div key={shelf.key} className="bookshelf">
                        <h2 className="bookshelf-title">{shelf.name}</h2>
                          <div className="bookshelf-books">
                            <ol className="books-grid">
                        <li>
                          { getBooksForShelf(shelf.key).map((book) => (
                            <div key={book.id} className="book">
                              <div className="book-top">
                               <div className="book-cover" style={{ width: 128, height: 193, backgroundImage: `url(${book.imageLinks.thumbnail})` }}></div>
                                <div className="book-shelf-changer"> 
                                 <select>
                                  <option value="none" disabled>Move to...</option>
                                    <option value="currentlyReading" onClick={() => onUpdateShelf(book, 'currentlyReading')} >Currently Reading</option>
                                    <option value="wantToRead" onClick={() => onUpdateShelf(book, 'wantToRead')} >Want to Read</option>
                                    <option value="read" onClick={() => onUpdateShelf(book, 'read')} >Read</option>
                                    <option value="none" onClick={() => onUpdateShelf(book, '')} >None</option>
                                   </select>
                                </div>
                              </div>
                              <div className="book-title">{book.title}</div>
                             <div className="book-authors">{book.author}</div>
                            </div>
                            ))}
                          </li>
                        </ol>
                        </div> 
                      </div>
                    )) }
                  </div>
                </div>
                <div className="open-search">
                  <a onClick={() => this.setState({ showSearchPage: true })}>Add a book</a>
                </div>
              </div>
            )}
          </div>
        )
    }
}

export default ListBooks

1 个答案:

答案 0 :(得分:1)

当您将updateShelf传递给组件ListBooks时,this内的updateShelf会失去价值,因此this.booksBooksApp未定义。

您可以通过在 this.updateShelf = this.updateShelf.bind(this)

的构造函数中执行此操作来解决此问题
<Route exact path='/' render={() => (
     <ListBooks
        books={this.state.books}
        onUpdateShelf={() => { this.updateShelf()} }
    />
)} />

或者使用箭头功能:

arrow functions

<击>

修改

您已在BooksApp内使用this.state.books,因此我之前所说的内容并非必要。

但是,你应该在this.books内使用updateShelf而不是from Folder1.Folder2.FileName import ModuleName someVar = ModuleName(params)