【问题标题】:Problem updating parent state from child component in React从 React 中的子组件更新父状态的问题
【发布时间】:2019-01-25 23:23:37
【问题描述】:

我有一个类组件(实际上是相同组件的集合),其中我有 2 个按钮 + 和 - 来增加和减少手表的数量。手表的最小数量是 1,最大数量是 10。我用这 2 个函数增加量处理程序和减少量处理程序来调节它。有了这两个按钮就OK了。但问题是我必须总结父组件中计算的手表的值,我不能将手表的总和值转发到父组件到状态变量totalAmount。不能使用 Redux,因为它是 watch 组件的集合,并且每个都有自己的 + 和 - 按钮已经被这 2 个 increaseAmountHandler 和 reductionAmountHandler 函数占用。 有人知道如何解决这个问题吗?

子组件:

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;

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    父母必须跟踪添加了多少手表。

    让父母聪明(有状态),让孩子愚蠢(无状态)。 管理父级中的所有状态,并将点击处理程序也放在父级中。

    将这些处理程序传递给子级,在单击其按钮时触发。像这样的:

    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>
      }
    }
    

    【讨论】:

    • Alan P. 我不能自己创建数据,它们是从表单文件中获取的
    • 好的,所以在我的示例中,this.state.watches 最初是一个空数组,并且在提交表单时会将对象添加到其中。
    • 要点保持不变:将状态保留在父级中,使子级无状态,并将更改父级状态的函数传递给子级。
    • Alan P. 你说的没错,在这种情况下只能从父组件控制。我做了很多修改,现在它正在工作。感谢您的帮助。
    • @AlanP。你能看看我的问题吗?这与stackoverflow.com/questions/65000877/… 非常相似
    猜你喜欢
    • 1970-01-01
    • 2021-04-02
    • 2019-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 2021-12-27
    • 2020-05-31
    相关资源
    最近更新 更多