【问题标题】:Changing the state from reusable component从可重用组件更改状态
【发布时间】:2022-01-14 01:11:27
【问题描述】:

我正在尝试通过可重用组件向主应用程序添加数据,问题是当我使用 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 组件的状态,我怎样才能使它工作,所以我可以进入书籍。

【问题讨论】:

  • addBook 中 setState 前添加 await (用于推送),并使用 componentDidUpdate 检测 props 更新

标签: javascript reactjs reactstrap


【解决方案1】:

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

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

你出错的地方就是你接下来要做什么。 &lt;BookModal /&gt; 组件应该只关心显示它给出的道具,但是您花费大量代码基本上将道具存储在BookModal 的状态中。为什么? BookModal 在传递的道具中拥有所需的一切。

“但是,”你会说,“模式有一个表单,用户将使用它来添加一本新书。子组件BookModal 将如何将该数据传递给父组件App? "答案是不会! App 跟踪状态,因此 App 应该向其子级公开一个函数,该函数可以将一本书添加到状态。你怎么把这个给孩子?将其作为道具传递! 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>
    );
  }
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-25
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 2018-05-06
    • 1970-01-01
    • 1970-01-01
    • 2019-10-06
    相关资源
    最近更新 更多