草庐IT

javascript - React,如何从 parent 那里访问 child 的状态?无需更新 parent 的状态

coder 2024-07-27 原文

你好,我是 React 的新手,我很难全神贯注于整个状态管理以及通过状态和 Prop 传递数据。我确实理解标准的 react 方式是以单向方式传递数据 - 从 parent 到 child ,我已经为所有其他组件这样做了。 但是我有一个名为 Book 的组件,它会根据用户选择表单“阅读、想要阅读、当前正在阅读和无”来更改其“书架”状态。在呈现 Book 组件的 BookList 组件中,它需要能够读取 Book 的书架状态并在名为“read、wantToRead、currentlyReading 和 none”的部分下呈现正确的书籍。由于在这种情况下,Book 组件是从 BookList 组件呈现的,而 BookList 是父组件,我真的不明白如何使 BookList 能够访问 Book 的状态? BookList 组件:

import React, { Component } from 'react'
import { Link } from 'react-router-dom'

import Book from './Book'

class BookList extends Component {
  render(){
    const { books, shelf } = this.props


    return (
    <div className="list-books">
      <div className="list-books-content">
        <div className="list-books-title">
          <h1>MyReads</h1>
        </div>

        <div className="bookshelf">
          <h2 className="bookshelf-title">None</h2>
          {books.map((book)=> {
            console.log(book)
            if (shelf === ''){
              return <div className="bookshelf-books">
                    {/* <BookStateless book= {book} /> */}
                    <Book book = {book} />
                      {/* <BookStateless book= {book} /> */}
                    </div>

            }
          })}
        </div>


        <div className="bookshelf">
          <h2 className="bookshelf-title">Currently Reading</h2>
            {books.map((book)=> {
              if (shelf === 'currentlyReading'){
                return <div className="bookshelf-books">
                      {/* <BookStateless book= {book} /> */}
                      <Book book = {book} />
                      </div>
              }
              // console.log(this.book.title, this.book.state)
            })}
          </div>

          <div className="bookshelf">
            <h2 className="bookshelf-title">Want to Read</h2>
            {books.map((book)=> {
              if (shelf === 'wantToRead'){
                return <div className="bookshelf-books">
                      {/* <BookStateless book= {book} /> */}
                      <Book book = {book} />
                        {/* <BookStateless book= {book} /> */}
                      </div>
              }
              // console.log(this.book.title, this.book.state)
            })}
          </div>
          <div className="bookshelf">
            <h2 className="bookshelf-title">Read</h2>
            {books.map((book)=> {
              if (shelf === 'read'){
                console.log(shelf)
                return <div className="bookshelf-books">
                      {/* <BookStateless book= {book} /> */}
                      <Book book = {book} />
                      </div>
              }
              // console.log(this.book.title, this.book.state)
            })}
          </div>

      </div>
      <div className="open-search">
        <Link to="/search">Add a book</Link>
      </div>
    </div>
    )
  }
}

export default BookList

图书组件:

import React, { Component } from 'react'
// import * as BooksAPI from './BooksAPI'

import Select from 'react-select'
import 'react-select/dist/react-select.css'

class Book extends Component {
  state={
    // state can be read, none, want to read, or currently reading
    shelf: ''
  }


  handleChange(e){
    this.setState({ shelf: e['value'] })
    console.log("this?", this)
  }



  render(){
    const { book } = this.props
    const { shelf } = this.state
    console.log("book", book.state)

    const options = [
      { value: 'currentlyReading', label: 'currentlyReading'},
      { value: 'wantToRead', label: 'wantToRead'},
      { value: 'read', label: 'read'},
      { value: 'none', label: 'none'}
    ]

    return (
      <li key={book.id}>
        <div className="book">
          <div className="book-top">
            <div className="book-cover" style={{ width: 128, height: 188, backgroundImage: `url("${book.imageLinks.thumbnail}")` }}></div>
            <div className="book-shelf-changer">

              <Select
                value=""
                options={options}
                onChange={(e)=>this.handleChange(e)}
              />


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

    )
  }
}

export default Book

在我的 app.js 中我有:

import React from 'react'
import * as BooksAPI from './BooksAPI'
import './App.css'
import Search from './Search'
import BookList from './BookList'
import Book from './Book'


import { Route } from 'react-router-dom'

class BooksApp extends React.Component {


  state = {
    books : []

  }

  componentDidMount(){
    BooksAPI.getAll().then((books)=> {
      this.setState({ books: books })
      // console.log("bookstest",this)
    })
  }


  render() {
    return (
      <div className="App">
        <Route exact path="/" render={()=>(
          <Book books={this.state.books} />
        )} />
        <Route path="/search" render={()=>(
          <Search books={this.state.books} />
        )} />
        <Route path="/BookList" render={()=>(
          <BookList books={this.state.books} />
        )} />

      </div>
      )
    }
  }

export default BooksApp

现在,当我在浏览器中打开 booklist 组件时,我看不到任何书籍,因为它没有在此处的任何 if 语句中获取状态:

if (shelf === 'currentlyReading'){
                return <div className="bookshelf-books">
}

非常感谢您提前通读,如有任何帮助,我们将不胜感激! 谢谢!

最佳答案

您不需要“访问”子级的状态,您可以将回调处理程序从父级传递给子级,当在子级内部触发事件时,您可以通过该事件处理程序(回调)通知父级。
我将发布一个小示例:

class Book extends React.Component {
  handleClick = e => {
    const { bookId, onToggleBook } = this.props;
    onToggleBook(bookId);
  };

  render() {
    const { name, isRead } = this.props;
    return (
      <div className={`${isRead && "read"}`} onClick={this.handleClick}>
        <span>{name}</span>
        {isRead && <i> - You read me</i> }
      </div>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      books: [
        {
          id: 1,
          name: "book 1",
          isRead: false
        },
        {
          id: 2,
          name: "book 2",
          isRead: false
        },
        {
          id: 3,
          name: "book 3",
          isRead: true
        },
        {
          id: 4,
          name: "book 4",
          isRead: false
        }
      ]
    };
  }

  onToggleBookStatus = bookid => {
    const { books } = this.state;
    const nextBookState = books.map(book => {
      if (book.id !== bookid) return book;
      return {
        ...book,
        isRead: !book.isRead
      };
    });
    this.setState(prevState => ({ books: nextBookState }));
  };

  render() {
    const { books } = this.state;
    return (
      <div>
        <div>My Books</div>
        {books.map(book => (
          <Book
            key={book.id}
            isRead={book.isRead}
            name={book.name}
            bookId={book.id}
            onToggleBook={this.onToggleBookStatus}
          />
        ))}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
.read {
  color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

关于javascript - React,如何从 parent 那里访问 child 的状态?无需更新 parent 的状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46632830/

有关javascript - React,如何从 parent 那里访问 child 的状态?无需更新 parent 的状态的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  5. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  6. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  7. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  8. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  9. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐