繁体   English   中英

如何从Reactjs中的子组件更新父组件的状态

[英]How to update a parent's component state from a child component in Reactjs

我正在将父组件的状态从父组件传递到子组件。在子组件中,我有一个不同的状态。我正在对子组件的状态执行一些操作,并且必须将其结果添加到因此,在我的父组件中,我编写了一个回调函数,该函数将更新父组件的状态。代码为:

updateState = (booksList) => {
          this.setState({books : this.state.books.push(booksList)});
        }

因此,此函数然后作为道具传递给子组件:

<BookSearch
   books={this.state.books}
   handleShelfChange={this.handleShelfChange}
   updateState={this.updateState}/>

然后在我的子组件中,我试图将回调函数实现为:

let getBook = this.state.books.filter(filteredBook => filteredBook.shelf !== "none")
    this.props.updateState(getBook)

但这不能按预期工作,这是正确的方法吗,有人可以帮我吗?

我试图通过实现此处提供的解决方案来解决我的问题: 如何在ReactJS中将数据从子组件传递到其父组件? ,但出现一些错误。

编辑

父组件:App.js

import React from 'react'
import * as BooksAPI from './BooksAPI'
import { Link } from 'react-router-dom'
import { Route } from 'react-router-dom'
import './App.css'
import BookList from './BookList'
import BookSearch from './BookSearch'


class BooksApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      books: [],
      showSearchPage : false
    };
    //this.updateState = this.updateState.bind(this)
  }

  componentDidMount() {
    BooksAPI.getAll().then((books) => {
      this.setState({ books })
    })
    console.log(this.state.books);
  }

  filterByShelf = (bookName,shelfName) =>
   bookName.filter(book => book.shelf===shelfName)


  isTheBookNew = book => {
    let is = false;
    if (book.shelf === "none")
     { this.setState(state =>
       {
         books: state.books.push(book)});
          is = true;
          console.log(this.state.books);
       }
       return is;
      };

      handleShelfChange = (bookOnChange, newSehlf) => {
         !this.isTheBookNew(bookOnChange) && this.setState(state => {
         let newBooks = state.books.map(book =>
           { if (bookOnChange.id === book.id)
             { book.shelf = newSehlf; }
             return book;
           });
             return {
                books: newBooks
               };
              }
            );
            BooksAPI.update(bookOnChange, newSehlf);
            };

        updateState = (booksList) => {
          const books = [...this.state.books, booksList]
          this.setState({ books });
        }

  render() {
    return (
      <div className="app">
        <Route exact path="/" render={() => (
          <div className="list-books">
              <div className="list-books-title">
                <h1>MyReads</h1>
              </div>

              <BookList
              books={this.filterByShelf(this.state.books,'currentlyReading')}
              shelfName='Currently Reading'
              handleShelfChange={this.handleShelfChange}/>

              <BookList
              books={this.filterByShelf(this.state.books,'wantToRead')}
              shelfName='Want to Read'
              handleShelfChange={this.handleShelfChange}/>

              <BookList
              books={this.filterByShelf(this.state.books,'read')}
              shelfName='Read'
              handleShelfChange={this.handleShelfChange}/>

              <div className="open-search">
                <Link
                to="./search" />
              </div>
          </div>
        )
      } />

            <Route path="/search" render={() =>
                <BookSearch
                 books={this.state.books}
                 handleShelfChange={this.handleShelfChange}
                 updateState={this.updateState}/>
              } />

      </div>
    )
  }
}

export default BooksApp

BookSearch.js:

import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import escapeRegExp from 'escape-string-regexp'
import  sortBy from 'sort-by'
import * as BooksAPI from './BooksAPI'
import BookList from './BookList'

class BookSearch extends Component {
  constructor(props) {
    super(props);
    this.state = {
      search:'',
      books:[]
    }
  }

  updateSearch = (searchString) => {
    this.setState({search: searchString.trim()})
    let searchResults = BooksAPI.search(this.state.search,1).then((book_search) => {
      if (book_search != undefined) {
        console.log(book_search);
          book_search.map((book) => book.shelf = 'none');
          this.setState({ books : book_search }, this.check); // callback function to this.setState
          console.log(this.state.books)
        }
    })

    }


  check = () => {
    let parent_books = this.props.books;
    console.log(this.state.books)
    const book_result = this.state.books.map((book) => {
      const parent = parent_books.find(parent => parent.title === book.title );
       if(parent) {
        //console.log(parent);
        book.shelf = parent.shelf;
        //console.log(book)
          }

        return book;
      })
    this.setState({books: book_result}, () => {console.log(this.state.books)})
  }

  updateParentState = () => {
    let getBook = this.state.books.filter(filteredBook => filteredBook.shelf !== "none")
    this.props.updateState(getBook)

  }

  render() {
    return(

      <div className="search-books">
        <div className="search-books-bar">
          <Link
            to="/"
            className="close-search">
            Close
          </Link>
          <div className="search-books-input-wrapper">
            <input
             type="text"
             placeholder="Search by title or author"
             value={this.state.search}
             onChange={(event) => this.updateSearch(event.target.value)}/>
          </div>
        </div>

        <div className="search-books-results">
          <ol className="books-grid">
            <BookList
              books={this.state.books}
              handleShelfChange={this.props.handleShelfChange}
              updateParentState={this.updateParentState}/>
          </ol>
        </div>
      </div>
    )
  }
}

export default BookSearch

BookList.js

import React, { Component } from 'react';
import Book from './Book'

class BookList extends Component {
constructor(props) {
  super(props);
  this.state = {
    showSearchPage : false
  }
  console.log(this.props.books)
}


  render() {
    return(
      <div className="app">
          <div>
           <div className="list-books-content">
              <div>
                <div className="bookshelf">
                  <h2 className="bookshelf-title">{this.props.shelfName}</h2>
                  <div className="bookshelf-books">
                    <ol className="books-grid">

                      {this.props.books.map(book =>
                        <li key={book.title}>
                          <Book
                          book={book}
                          handleShelfChange={this.props.handleShelfChange}
                          update={this.props.updateParentState} />
                        </li>)
                      }
                    </ol>
                  </div>

                </div>
              </div>
            </div>
          </div>
    </div>
    )
  }
}


export default BookList;

Book.js

import React, { Component } from 'react'

class Book extends Component {
  constructor(props) {
    super(props);
    this.props.updateParentState;
  }

  render() {
    return(
      <div className="book">
        <div key={this.props.book.title}>
          <div className="book-top">
            <div className="book-cover" style={{width:128, height:193, backgroundImage: `url(${this.props.book.imageLinks.thumbnail})`}}>
                  <div className="book-shelf-changer">
                    <select id="bookName" value={this.props.book.shelf}
                      onChange={(event) => this.props.handleShelfChange(this.props.book, event.target.value)}>
                      <option value="moveTo" disabled>Move to...</option>
                      <option value="currentlyReading">Currently Reading</option>
                      <option  value="wantToRead">Want to Read</option>
                      <option  value="read">Read</option>
                      <option value="none">None</option>
                    </select>

                  </div>
            </div>
          </div>
          <div className="book-title">{this.props.book.title}</div>
          <div className="book-authors">{this.props.book.authors}</div>
        </div>

  </div>
      )
  }
}

export default Book

因此,我有4个组件,如上所示。从App组件中,我正在调用BookSearch组件,在其中可以搜索书籍,并通过选择下拉列表中的值将书籍发送到App组件。 最初,BookSearch组件中的每本书都会被分配一个“ none”的书架属性。当用户从Booksearch中选择一个书架值时,该书将自动添加到App组件中。因此,当我从BookSearch导航回到App组件时,我应该能够在分配的书架上看到这本书。因此,在这种情况下,我正在使用updateSearch函数。 书籍通过具有下拉值的“书籍”组件显示。

如果我正确理解这一点,则说明您正在对状态updateState的状态进行变异。

您应该做的是,

const updateState = (booksList) => {
   const books = [ ...this.state.books, ...booklist ];
   this.setState({ books });
}

在父组件构造函数中添加以下行:

this.updateState = this.updateState.bind(this)

有关更多信息, 访问https://reactjs.org/docs/handling-events.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM