如何动态更改已经渲染的组件的状态?

时间:2019-07-23 11:25:34

标签: reactjs

我正在构建我的第一个React应用程序,并且正在做一个人们可以用来与其他人分开账单的应用程序。通过此链接http://split-calc.herokuapp.com,该应用程序已部署在heroku上。

我遇到的问题如下:

让我们假设您首先输入100作为“膳食”,20作为“共享项目”,然后输入10作为“税费和小费”,这样总计140。

接下来,单击“添加人”按钮,该按钮将呈现“人”组件。在这里,您将看到“个人小计”的输入。共享会自动从20开始,因为到目前为止您只能自己分摊账单。当您向“个人小计”添加值时,小费,税金和总计会动态更新。现在问题出在再次单击“添加人”时。第2个人现在的碎片价值为10,这是正确的,因为现在“共享物品”(即$ 20)现在被两个人(20/2 = 10)分割。问题是,第1个人的共享价值仍然为$ 20。现在,如果再次单击“添加人”,则第三人将具有正确的共享值,但是现在人#1和#2具有过时的值。如何动态更新这些内容?

下面是我到目前为止的所有代码。

function Header() {
    return (
        <header>Split Bill Calculator</header>
    )
}


function AddPerson(props) {
    return (
        <div className='button'>
            <button className='addPerson' onClick={props.onClicked}>Add Person</button>
        </div>
    );
}


function PersonList(props) {
    return (
        <div>
        {props.persons.map((person, index) => (
            <span key={index}>{person}</span>
        ))}
        </div>
    );
};


class Details extends React.Component {
    constructor(props) {
        super(props); 
            this.state = {
                meal_total: 0,
                shared_items: 0,
                tax: 0,
                tip: 0,
                persons: [],
                counter: 1,
            };
            this.handleClick = this.handleClick.bind(this)
            this.handleMealChange = this.handleMealChange.bind(this)
            this.handleSharedItemsChange = this.handleSharedItemsChange.bind(this)
            this.handleTaxChange = this.handleTaxChange.bind(this)
            this.handleTipChange = this.handleTipChange.bind(this)

    }

    handleMealChange = event => {
        this.setState({
            meal_total: event.target.value,
        });
    };

    handleSharedItemsChange = event => {
        this.setState({
            shared_items: event.target.value,
        });
    };

    handleTaxChange = event => {
        this.setState({
            tax: event.target.value,
        });
    };

    handleTipChange = event => {
        this.setState({
            tip: event.target.value,
        });
    };

    handleClick = () => {
        let counter = this.state.counter + 1
        let addPerson = this.state.persons.concat(this.renderPerson())
        this.setState({
            persons: addPerson,
            counter: counter,
        });
    }

    renderPerson = () => {
        return (
            <Person
                person_tax = {this.state.tax}
                person_tip = {this.state.tip}
                shared_items = {this.state.shared_items}
                counter = {this.state.counter}
            />
        )
    }

    renderAddPerson = () => {
        return (
            <AddPerson 
                onClicked= {() => this.handleClick()}    
                />
        );
    }

    render() {
        let grand_total = parseFloat(this.state.meal_total) + ((parseFloat(this.state.meal_total)) * (parseFloat(this.state.tax)/100)) + ((parseFloat(this.state.meal_total)) * (parseFloat(this.state.tip)/100));
        return (
            <div className='details'>
                <div className='order-total'>
                    <form>
                        <label htmlFor='meal'>Meal subtotal: ($)</label><br></br>
                        <input name='meal' placeholder={this.state.meal_total} onChange={this.handleMealChange}></input><br></br>
                        <label htmlFor='meal'>Shared items: ($)</label><br></br>
                        <input name='meal' placeholder={this.state.shared_items} onChange={this.handleSharedItemsChange}></input><br></br>
                        <label htmlFor='tax'>Tax: (%)</label><br></br>
                        <input name='tax' placeholder={this.state.tax} onChange={this.handleTaxChange}></input><br></br>
                        <label htmlFor='tip'>Tip: (%)</label><br></br>
                        <input name='tip' placeholder={this.state.tip} onChange={this.handleTipChange}></input><br></br>
                        <label htmlFor='total'>Grand Total: ($)</label><br></br>
                        <input name='total' value={grand_total.toFixed(2)} readOnly></input><br></br>
                    </form>
                </div>
                <PersonList persons={this.state.persons} />
                {this.renderAddPerson()}
            </div>
        );
    }
}


class Person extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            person_tax: props.person_tax,
            person_tip: props.person_tip,
            person_meal_subtotal: 0,
            shared_items: props.shared_items,
        }
    }

    handlePersonSubtotal = event => {
        this.setState({
            person_meal_subtotal: event.target.value
        });
    };

    render() {
        let person_total = parseFloat(this.state.person_meal_subtotal) + parseFloat(this.props.shared_items) + ((parseFloat(this.state.person_meal_subtotal)) * (parseFloat(this.state.person_tax)/100)) + ((parseFloat(this.state.person_meal_subtotal)) * (parseFloat(this.state.person_tip)/100));
        let shared_items = this.state.shared_items / this.props.counter;
        return (
            <div className='person'>
                <div className='total-details'>
                    <h3>Person {this.props.number} </h3>
                    <form>
                        <label htmlFor='person-meal'>Personal Subtotal: $ </label>
                        <input name='person-meal' value={this.state.person_meal_subtotal} onChange={this.handlePersonSubtotal}></input>
                    </form>
                </div>
                <div className='breakdown'>
                    <h3>Should Pay</h3>
                    <div className='person-details'>
                        <p>Shared: ${(parseFloat(shared_items)).toFixed(2)}</p>
                        <p>Tax: ${((parseFloat(this.state.person_tax)/100) * parseFloat(this.state.person_meal_subtotal)).toFixed(2)}</p>
                        <p>Tip: ${((parseFloat(this.state.person_tip)/100) * parseFloat(this.state.person_meal_subtotal)).toFixed(2)}</p>
                        <p>Total: ${person_total.toFixed(2)}</p>
                    </div>
                </div>    
            </div>
        )
    }
}




class Calculator extends React.Component {
    render() {
        return (
            <div>
                <Header />
                <Details/>
            </div>
        )
    }
}


ReactDOM.render(<Calculator />, document.getElementById('root'));

1 个答案:

答案 0 :(得分:0)

You might want to do it later
 handleClick = () => {
        let counter = this.state.counter + 1
        let addPerson = this.state.persons.concat(this.renderPerson())
        this.setState({
            persons: addPerson,
            counter: counter,
        });
    }
instead of this
try this

     handleClick = () => {
            let counter = this.state.counter + 1
            this.setState({
                persons: addPerson,
                counter: counter,
            }, () => {
     let addPerson = this.state.persons.concat(this.renderPerson())
            this.setState({
                persons: addPerson
            });
    });
    }