单击后React组件未更新

时间:2019-07-23 14:00:28

标签: reactjs

我刚刚创建了我的第一个React应用https://split-calc.herokuapp.com/

如果我先填写顶部表格,然后单击“添加人”,则一切正常。但是,如果我在填写顶部表格之前单击“添加人员”,则在填写顶部表格后,不会更新人员编号。即使我将每个值都设置为链接到状态,为什么会发生这种情况?


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.counter} </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><br></br>
                        <p>Tax: ${((parseFloat(this.state.person_tax)/100) * parseFloat(this.state.person_meal_subtotal)).toFixed(2)}</p><br></br>
                        <p>Tip: ${((parseFloat(this.state.person_tip)/100) * parseFloat(this.state.person_meal_subtotal)).toFixed(2)}</p><br></br>
                        <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)

第一个建议是,如果表单未填写,则不允许用户添加人员。

基于对上面代码的分析,您没有将状态与对象的人数数组链接,也没有更新值。每次更改仅更新有关状态的全局数据。

this.state = {
    meal_total: 0, /*updated*/
    shared_items: 0, /*updated*/
    tax: 0, /*updated*/
    tip: 0, /*updated*/
    persons: [], /*not updated on each action update, its only getting re-render or getting the state during new person add action*/
    counter: 1, /*updated*/
};

您需要更新state.persons:[]每个动作到唯一的person数组

handleTaxChange = event => {
        this.setState({
            tax: event.target.value,
            persons: <-- update the number of persons selected array with tax  -->
        });
    };

调用渲染人员列表的代码,每次渲染时似乎都有旧值->

<PersonList persons={this.state.persons} />

您需要访问并更新个人税。

快乐编码!