簡體   English   中英

從 React 中的子組件更新父狀態的問題

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

我有一個類組件(實際上是相同組件的集合),其中我有 2 個按鈕 + 和 - 來增加和減少手表的數量。 手表的最小數量是 1,最大數量是 10。我已經用這 2 個函數增加數量和減少數量來調節這個。 有了這兩個按鈕就沒事了。 但問題是我必須對父組件中計算的手表的值求和,我不能將手表的總和值轉發給父組件以聲明變量 totalAmount。 不能使用 Redux,因為它是一個手表組件的集合,每個都有自己的 + 和 - 按鈕已經被這 2 個增加數量處理程序,減少數量處理程序占用了。 任何人都知道如何解決這個問題?

子組件:

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;

父組件:

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;

父級必須跟蹤添加了多少手表。

讓父節點變聰明(有狀態),讓孩子變傻(沒有狀態)。 管理父級中的所有狀態,並將點擊處理程序也放在父級中。

將這些處理程序傳遞給子級,在單擊其按鈕時觸發。 像這樣的東西:

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