简体   繁体   English

从 React 中的子组件更新父状态的问题

[英]Problem updating parent state from child component in React

I have a class component(actually the collection of the same components) where I have 2 buttons + and - to increase and decrease quantity of watches.我有一个类组件(实际上是相同组件的集合),其中我有 2 个按钮 + 和 - 来增加和减少手表的数量。 Min amount of watches is 1 and max amount is 10. I have regulated this with this 2 functions increaseAmountHandler and decreaseAmountHandler.手表的最小数量是 1,最大数量是 10。我已经用这 2 个函数增加数量和减少数量来调节这个。 With this two buttons it's all ok.有了这两个按钮就没事了。 But the problem is that I have to sum up the value of calculated watches in parent component and I cannot forward the summed up values of the watches to a parent component to state variable totalAmount.但问题是我必须对父组件中计算的手表的值求和,我不能将手表的总和值转发给父组件以声明变量 totalAmount。 Cannot use Redux becacuse it's a collection of watches component and each have own + and - button already occupied with this 2 increaseAmountHandler, decreaseAmountHandler functions.不能使用 Redux,因为它是一个手表组件的集合,每个都有自己的 + 和 - 按钮已经被这 2 个增加数量处理程序,减少数量处理程序占用了。 Anyone idea how to solve this?任何人都知道如何解决这个问题?

Child component:子组件:

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

class SelectedWatch extends Component {
    constructor(props) {
        super(props)

        this.state = {
            watchQuantity: 1,
            watchAmount: 1
        }
    }

    increaseAmountHandler = () => {
        if(this.state.watchQuantity < 1) {
            this.setState({
                watchQuantity: 0, 
                watchAmount: 0
            })
            return;
        } else if (this.state.watchQuantity >= 10){
            this.setState({
                watchQuantity: 10,
                watchAmount: this.props.selectedWatch.selectedWatchPrice * this.state.watchQuantity
            })
            return;
        }

        this.setState({
            watchQuantity: this.state.watchQuantity + 1,
            watchAmount: this.props.selectedWatch.selectedWatchPrice * this.state.watchQuantity
        })
    }

    decreaseAmountHandler = () => {
        if(this.state.watchQuantity < 1) {
            this.setState({
                watchQuantity: 0,
                watchAmount: 0
            })
            return;
        } else if (this.state.watchQuantity >= 10){
            this.setState({
                watchQuantity: 9,
                watchAmount: this.props.selectedWatch.selectedWatchPrice * this.state.watchQuantity
            })
            return;
        }

        this.setState({
            watchQuantity: this.state.watchQuantity - 1,
            watchAmount: this.props.selectedWatch.selectedWatchPrice * this.state.watchQuantity
        })
    }

    render() {
        return (
            <div className={"shopping-cart-product" + (this.state.watchQuantity < 1 ? ' notDisplayed' : '')}>
                <div className="product-info">
                    <div>
                        <h3>{this.props.selectedWatch.selectedWatchName}</h3>
                        <p>${this.props.selectedWatch.selectedWatchPrice} &times; {this.state.watchQuantity}</p>
                    </div>
                    <img src={this.props.selectedWatch.selectedWatchUrl} />
                </div>
                <div className="product-count">
                    <button onClick={this.decreaseAmountHandler}>-</button>
                    <span>{this.state.watchQuantity}</span>
                    <button onClick={this.increaseAmountHandler}>+</button>
                </div>
            </div>
        );
    }
}
export default SelectedWatch;

Parent component:父组件:

import React, { Component } from 'react';
import EnteredWatch from '.././components/EnteredWatch/EnteredWatch';
import SelectedWatch from '.././components/SelectedWatch/SelectedWatch';

class App extends Component {
    constructor(props) {
        super(props)

        this.state = {
            watchName: '',
            watchDescription: '',
            watchUrl: '',
            watchPrice: '',
            watchId: '',
            watchAmount: '',
            watchQuantity: 1, 
            enteredWatchList: [],
            selectedWatchName: '',
            selectedWatchDescription: '',
            selectedWatchUrl: '',
            selectedWatchPrice: '',
            selectedWatchId: '',
            selectedWatchAmount: '', 
            selectedWatchQuantity: 1, 
            selectedWatchList: [],
            totalAmount: 0,
        }
    }

        submitHandler = (event) => {

            event.preventDefault();

            let watchId = Math.floor((Math.random() * 100) + 1);
            let watchName = this.state.watchName;
            let watchDescription = this.state.watchDescription;
            let watchUrl = this.state.watchUrl;
            let watchPrice = this.state.watchPrice;
            let watchQuantity = this.state.watchQuantity;

            this.setState({
                enteredWatchList: this.state.enteredWatchList.concat({watchName, watchUrl, watchDescription, watchPrice, watchId, watchQuantity})
            })

        add = (selectedWatchName, selectedWatchUrl, selectedWatchDescription, selectedWatchPrice, index, selectedWatchQuantity) => {

            let arr = this.state.selectedWatchList;

            let found = arr.some(el => {
                return el.selectedWatchName === selectedWatchName;
            });

            if (!found) { 
                return arr.concat({selectedWatchName, selectedWatchUrl, selectedWatchDescription, selectedWatchPrice, index, selectedWatchQuantity});
            } else {
                return this.state.selectedWatchList;
            }

        }

        buyWatchHandler = (selectedWatchName, selectedWatchUrl, selectedWatchDescription, selectedWatchPrice, index, selectedWatchQuantity) => {

            let arr = this.add(selectedWatchName, selectedWatchUrl, selectedWatchDescription, selectedWatchPrice, index, selectedWatchQuantity);

            this.setState({
                selectedWatchName: selectedWatchName,
                selectedWatchUrl: selectedWatchUrl,
                selectedWatchDescription: selectedWatchDescription,
                selectedWatchPrice: selectedWatchPrice,
                selectedWatchId: index,
                selectedWatchQuantity: selectedWatchQuantity, 
                selectedWatchList: arr
            });
        }

        render() {

            const enteredWatches = this.state.enteredWatchList.map((enteredWatch, index) => {
                return <EnteredWatch
                    key={index}
                    enteredWatch={enteredWatch}
                    selected={this.buyWatchHandler.bind(this, enteredWatch.watchName, enteredWatch.watchUrl,
                        enteredWatch.watchDescription, enteredWatch.watchPrice, index, enteredWatch.watchQuantity)}
                />
            });

            const selectedWatches = this.state.selectedWatchList.map((selectedWatch, index) => {
                const active = this.state.activeIndex;
                return <SelectedWatch
                    key={index}
                    active={index === active}
                    selectedWatch={selectedWatch}
                />
            });

            return (
                <div className="App">
                    <div className="container-fluid">
                        <div className="container">
                            <div className="add-product">
                               <form>
                                    <div>
                                        <label>Product name:</label>
                                        <input 
                                            type="text" 
                                            placeholder="Casio Watch" 
                                            required
                                            value={this.state.watchName}
                                            onChange={event => this.setState({watchName: event.target.value})}
                                        />
                                    </div>

                                    <div>
                                        <label>Product description:</label>
                                        <textarea 
                                            placeholder="Sample description..."
                                            value={this.state.watchDescription}
                                            onChange={event => this.setState({watchDescription: event.target.value})}
                                        >
                                        </textarea>
                                    </div>

                                    <div>
                                        <label>Product image:</label>
                                        <input 
                                            type="text" 
                                            placeholder="http://...jpg"
                                            value={this.state.watchUrl}
                                            pattern="https?://.+" required
                                            onChange={event => this.setState({watchUrl: event.target.value})}
                                        />
                                    </div>

                                    <div>
                                        <label>Product price:</label>
                                        <input 
                                            type="number" 
                                            min="0" 
                                            placeholder="22" 
                                            value={this.state.watchPrice}
                                            onChange={event => this.setState({watchPrice: event.target.value})}
                                        />
                                    </div>

                                    <button
                                        type="submit"
                                        onClick={event => this.submitHandler(event)}
                                    >
                                        Add a new Task
                                    </button>
                                </form>
                             </div>

                             <div className="list-products">
                                <ul>
                                   {enteredWatches}
                                </ul> 
                            </div>

                            <div className="shopping-cart">
                                <div className="shopping-cart-products">
                                    <ul>
                                       {selectedWatches}
                                    </ul> 

                                </div>
                                <div className="shopping-cart-summary">
                                    <div>Total: <b>${this.state.totalAmount}</b></div>
                                    <div><button onClick={this.summaryHandler}>Purchase</button></div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            );
        }
    }

    export default App;

The parent has to keep track of how many watches have been added.父级必须跟踪添加了多少手表。

Make the parent smart (has state), and the children dumb (no state).让父节点变聪明(有状态),让孩子变傻(没有状态)。 Manage all the state in the parent, and put the click handlers in the parent too.管理父级中的所有状态,并将点击处理程序也放在父级中。

Pass those handlers down to the child, to be fired when its buttons are clicked.将这些处理程序传递给子级,在单击其按钮时触发。 Something like this:像这样的东西:

class Parent extends React.Component {
  this.state = {
    cart: [],
    watches: [
      { id: 1, name: "Casio", description: "...", price: 25 },
      { id: 2, name: "Rolex", description: "...", price: 3000 },
      { id: 3, name: "Timex", description: "...", price: 10 },
    ],
  }

  handleClickIncrement = (watchId) => {
    //add it to the cart (or increment it if its already there)
  }

  handleClickDecrement = (watchId) => {
    //remove it from the cart (or deccrement it if its already there)
  }

  getCartTotal() {
    //loop over cart and calculate
  }

  renderWatches() {
    this.state.watches.map(watch => (
      <Watch id={watch.id}
        name={watch.name}
        description={watch.description}
        price={watch.price}
        onClickIncrement={() => { this.handleClickIncrement(watch.id); }} 
        onClickDecrement={() => { this.handleClickDecrement(watch.id); }} 
    ))
  }

  render() {
    <div>
      <h1>Our selection of watches:</h1>
      {this.renderWatches()}

      <h1>Your cart total: {this.getCartTotal()}</h1>
    </div>
  }
}


class Watch extends React.Component {
  props = {
    id,
    name,
    description,
    price,
    quantityInCart,
    onClickIncrementButton,
    onClickDecrementButton
  }

  render() {
    <div>
      <h1>{this.props.name}</h1>
      <p>{this.props.description}</p>
      <h5>${this.props.price}</h5>
      <button onClick={this.props.onClickIncrementButton}>+</button>
      <button onClick={this.props.onClickDecrementButton}>-</button>
    </div>
  }
}

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

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