从可重用组件更改状态

Changing the state from reusable component

我正在尝试通过可重用组件向主应用程序添加数据,问题是当我使用 setState 时,没有任何反应。

在主应用程序中,我正在调用 BookModal 并传递

state:

    state= {
    books: [
      {id: uuidv4(),name: 'The Kingkiller Chronicle', isbm:'5435-54',quantity: '4', price:'14.99', isBorrowed: false, remainingDays: 14},
      {id: uuidv4(),name: 'Jane Eyre', isbm:'643543-21',quantity: '2', price:'19.99', isBorrowed: false, remainingDays: -3}
    ],
    newBookModal: false,
    editBookModal: false,
    newBookData: {
      id: '',
      name: '',
      isbm: '',
      quantity:'',
      price: '',
      isBorrowed: false,
      remainingDays: 14
    },
    editBookData: {
      id: '',
      name: '',
      isbm: '',
      quantity:'',
      price: ''
    }
  }

我在这里渲染组件:

<BookModal booksData={this.state}/>

在模态中:

    import { Component } from 'react';
import React from 'react';
import {
  Button,
  Modal,
  ModalHeader,
  ModalBody,
  FormGroup,
  Label,
  Input,
  ModalFooter
 } from 'reactstrap';
 import { v4 as uuidv4 } from 'uuid';

class BookModal extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            newBookData: {
                id: '',
                name: '',
                isbm: '',
                quantity:'',
                price: '',
                isBorrowed: false,
                remainingDays: 14
              },
              newBookModal: false,
        }

        this.openNewBookModal  = this.openNewBookModal.bind(this);
        this.addBook = this.addBook.bind(this)
    }
     async openNewBookModal () {
         console.log(this.state.newBookModal);
        this.setState({
          newBookModal: !this.props.booksData.newBookModal//the opposite of the state
        });
      };

       addBook  () {
        let { books } = this.props.booksData;
        
        books.push(this.props.booksData.newBookData);
    
        await this.setState({ books, newBookModal: false, newBookData: {
          id: uuidv4(),
          name: '',
          isbm: '',
          quantity:'',
          price: '',
          isBorrowed: false
        }});
      }
render() {
  return(
    <Modal isOpen={this.props.booksData.newBookModal} toggle={this.openNewBookModal}>
    <ModalHeader toggle={this.openNewBookModal}>Add a new book</ModalHeader>
    <ModalBody>
      <FormGroup>
        <Label for="title">Title</Label>
        <Input id="title" value={this.props.booksData.newBookData.name}  onChange={(e) => {
          let { newBookData } = this.props.booksData;
          newBookData.name = e.target.value;
  
          this.setState({ newBookData });
        }} />
      </FormGroup>
  
      <FormGroup>
        <Label for="isbm">ISBM</Label>
        <Input id="isbm" value={this.props.booksData.newBookData.isbm}  onChange={(e) => {
          let { newBookData } = this.props.booksData;
  
          if (e.target.value === '' || e.target.value.match(/^\d{1,}(\-\d{0,2})?$/)) {
            newBookData.isbm = e.target.value;
          }
  
          this.setState({ newBookData });
        }} />
      </FormGroup>
  
      <FormGroup>
        <Label for="quantity">Quantity</Label>
        <Input id="quantity" value={this.props.booksData.newBookData.quantity}  onChange={(e) => {
          let { newBookData } = this.props.booksData;
  
          if (e.target.value === '' || e.target.value.match(/^\d{1,9}?$/)) {
            newBookData.quantity = e.target.value;
          }
  
          this.setState({ newBookData });
        }} />
      </FormGroup>
  
      <FormGroup>
        <Label for="price">Price</Label>
        <Input id="price" value={this.props.booksData.newBookData.price}  onChange={(e) => {
          let { newBookData } = this.props.booksData;
          if (e.target.value === '' || e.target.value.match(/^\d{1,}(\.\d{0,2})?$/)) {
            newBookData.price = e.target.value;
          }
  
          this.setState({ newBookData });
        }} />
      </FormGroup>
    </ModalBody>
    <ModalFooter>
      <Button color="primary" onClick={this.addBook}>Add Book</Button>{' '}
      <Button color="secondary" onClick={this.openNewBookModal}>Cancel</Button>
    </ModalFooter>
  </Modal>
       )
    }
}

export default BookModal;

问题似乎出在 addBook 上,因为它不知道 App 主组件的状态,我怎样才能让它工作,这样我才能进入书籍。

这段代码有一些问题,但我认为主要是概念上的问题。 React 鼓励您做的一件事是找到尽可能少的状态。

在您的应用中,App 组件似乎在处理应用程序的状态。它跟踪您需要以各种方式显示的数据,即书籍列表。然后,正如您应该的那样,将此数据作为道具传递给 child 组件,该组件将处理显示此数据,在本例中为模态。

哪里出错了,接下来就怎么做。 <BookModal /> 组件应该只关心显示它给定的 props,然而你花费了大量代码基本上将 props 存储在 BookModal 的状态。为什么? BookModal 传递的 props 中包含所需的一切。

“但是,”您会说,“模式有一个用户将用来添加新书的表单。child 组件 BookModal 将如何传递该数据parent、App?”答案是不会! App 跟踪状态,因此 App 应该向其 children 公开一个可以向状态添加一本书的函数。你如何把它送到 child?传递它作为道具! BookModal 唯一需要的状态是允许它 control the form components.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {books: []};
  }

  addBook(bookToAdd) {
    // instead of using push, which mutates the state (generally a bad idea), we'll make a copy of the state books array using the ES6 spread operator and add the new book
    this.setState({ books: [...this.state.books, bookToAdd ] });
  }

  render() {
    return (
      {/* you don't even really need to pass the app state down to this component if all it does is render a form, but we'll leave it for now */}
      <BookModal data={this.state} addBook={this.addBook} />
    );
  }
}
class BookModal extends React.Component {
  constructor(props) {
    super(props);
    this.state = { 
      title: '',
      isbn: '',
      quantity: '0',
      price: '0',
    }
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit() {
    // call the function we have been passed as a prop with the new book and let the App component handle the change in our application state
    const bookToAdd = { 
      title: this.state.title,
      isbn: this.state.isbn,
      quantity: this.state.quantity,
      price: this.state.price,
    }
    this.props.addBook(bookToAdd);
  }
  
  render() {
    return (
      <Modal>
        <FormGroup>
          <Label for="title">Title</Label>
          <Input id="title" value={this.state.title} onChange={(e) => this.setState({title: e.target.value})} />
        </FormGroup>
        <FormGroup>
          <Label for="isbn">ISBN</Label>
          <Input id="isbn" value={this.state.isbn} onChange={(e) => this.setState({isbn: e.target.value})}/>
        </FormGroup>
        <FormGroup>
          <Label for="quantity">Quantity</Label>
          <Input id="quantity" value={this.state.quantity} onChange={(e) => this.setState({quantity: e.target.value})}/>
        </FormGroup>
        <FormGroup>
          <Label for="isbn">Price</Label>
          <Input id="price" value={this.state.price} onChange={(e) => this.setState({isbn: e.target.value})}/>
        </FormGroup>
        <Button color="primary" onClick={this.handleSubmit}>Add Book</Button>
      </Modal>
    );
  }
}

编辑:我有一段时间没有使用 class 组件,如果这里有小错误,我们深表歉意(不敢相信我们曾经 bind!)。希望我的主要观点得到理解。