admin管理员组

文章数量:1317906

I've recently picked up react and I'm attempting to create a calculator as a leaning exercise for myself.

The aim is that whenever I click on a number button then that value will appear in the input ponent. So far I have got this to work but the value only changes on the second onClick event.

Currently the val1 prop disappears from the input on first click and then reappears on the second click with the previous button value.

Any tips on the structure of my code are more than wele and any guidance going forward with the build of my calculator would also be great. I am still very new to this.

Here's my code below:

app.js

import React, {Component} from 'react';
import InputField from './Components/InputField';
import Numbers from './Components/Numbers';
import './App.css';

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            number: 0,
            val1: 0,
            val2: 0
        }
    }
    numberChange(num1, num2){
        this.setState({val1: num1});
    }
    render() {
        return (
            <div className="App">
                <InputField val1={this.state.val1} value={this.state.number || ''} onChange={this.numberChange.bind(this)} />
                <Numbers onChange={this.numberChange.bind(this)} />
            </div>
        );
    }
}

export default App;

InputField.js

import React, {Component} from 'react';

class InputField extends Component {
    constructor(props) {
        super(props);
        this.state = {
            number: 0
        }
    }
    onChange(e) {
        console.log('onChange event fired');
        this.setState({
            number: e.target.value
        })
        this.props.onChange(this.state.number);
        console.log(this.state.number);
    }
    render() {
        return (
            <div className="inputField">
                <input type="number" value={this.props.val1 || ''} onChange={this.onChange.bind(this)}/>
            </div>
        );
    }
}

export default InputField;

Numbers.js

import React, {Component} from 'react';
import {Button} from 'react-bootstrap'

class Numbers extends Component {
    constructor(props) {
        super(props);
        this.state = {
            number: props.value
        }
    }
    number(e) {
        console.log('You\'ve pressed number ' + e.target.value);
        this.setState({
            number: e.target.value
        })
        this.props.onChange(this.state.number);
    }
    render() {
        return (
            <div className="buttons">
                <Button bsStyle="primary" value="1" onClick={this.number.bind(this)}>1</Button>
                <Button bsStyle="primary" value="2" onClick={this.number.bind(this)}>2</Button>
                <Button bsStyle="primary" value="3" onClick={this.number.bind(this)}>3</Button>
                <Button bsStyle="primary" value="4" onClick={this.number.bind(this)}>4</Button>
                <Button bsStyle="primary" value="5" onClick={this.number.bind(this)}>5</Button>
                <Button bsStyle="primary" value="6" onClick={this.number.bind(this)}>6</Button>
                <Button bsStyle="primary" value="7" onClick={this.number.bind(this)}>7</Button>
                <Button bsStyle="primary" value="8" onClick={this.number.bind(this)}>8</Button>
                <Button bsStyle="primary" value="9" onClick={this.number.bind(this)}>9</Button>
            </div>
        );
    }
}

export default Numbers;

Any help would be greatly appreciated!

I've recently picked up react and I'm attempting to create a calculator as a leaning exercise for myself.

The aim is that whenever I click on a number button then that value will appear in the input ponent. So far I have got this to work but the value only changes on the second onClick event.

Currently the val1 prop disappears from the input on first click and then reappears on the second click with the previous button value.

Any tips on the structure of my code are more than wele and any guidance going forward with the build of my calculator would also be great. I am still very new to this.

Here's my code below:

app.js

import React, {Component} from 'react';
import InputField from './Components/InputField';
import Numbers from './Components/Numbers';
import './App.css';

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            number: 0,
            val1: 0,
            val2: 0
        }
    }
    numberChange(num1, num2){
        this.setState({val1: num1});
    }
    render() {
        return (
            <div className="App">
                <InputField val1={this.state.val1} value={this.state.number || ''} onChange={this.numberChange.bind(this)} />
                <Numbers onChange={this.numberChange.bind(this)} />
            </div>
        );
    }
}

export default App;

InputField.js

import React, {Component} from 'react';

class InputField extends Component {
    constructor(props) {
        super(props);
        this.state = {
            number: 0
        }
    }
    onChange(e) {
        console.log('onChange event fired');
        this.setState({
            number: e.target.value
        })
        this.props.onChange(this.state.number);
        console.log(this.state.number);
    }
    render() {
        return (
            <div className="inputField">
                <input type="number" value={this.props.val1 || ''} onChange={this.onChange.bind(this)}/>
            </div>
        );
    }
}

export default InputField;

Numbers.js

import React, {Component} from 'react';
import {Button} from 'react-bootstrap'

class Numbers extends Component {
    constructor(props) {
        super(props);
        this.state = {
            number: props.value
        }
    }
    number(e) {
        console.log('You\'ve pressed number ' + e.target.value);
        this.setState({
            number: e.target.value
        })
        this.props.onChange(this.state.number);
    }
    render() {
        return (
            <div className="buttons">
                <Button bsStyle="primary" value="1" onClick={this.number.bind(this)}>1</Button>
                <Button bsStyle="primary" value="2" onClick={this.number.bind(this)}>2</Button>
                <Button bsStyle="primary" value="3" onClick={this.number.bind(this)}>3</Button>
                <Button bsStyle="primary" value="4" onClick={this.number.bind(this)}>4</Button>
                <Button bsStyle="primary" value="5" onClick={this.number.bind(this)}>5</Button>
                <Button bsStyle="primary" value="6" onClick={this.number.bind(this)}>6</Button>
                <Button bsStyle="primary" value="7" onClick={this.number.bind(this)}>7</Button>
                <Button bsStyle="primary" value="8" onClick={this.number.bind(this)}>8</Button>
                <Button bsStyle="primary" value="9" onClick={this.number.bind(this)}>9</Button>
            </div>
        );
    }
}

export default Numbers;

Any help would be greatly appreciated!

Share Improve this question asked Jan 18, 2017 at 17:42 AngryFridgesAngryFridges 4136 silver badges13 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

setState is an asynchronous function, meaning the data is only updated after you have called the onChange callback function. Therefore the App Component still gets the old value of this.state.number.

Try calling the onChange function after the setState is finished by:

number(e) {
    console.log('You\'ve pressed number ' + e.target.value);
    this.setState({
        number: e.target.value
    }, () => {
        this.props.onChange(this.state.number);
    })
}

More info here

this.setState is async, then this.props.onChange(this.state.number); is called before the state really changed, and thus state.number has the old value,, you should do this: this.props.onChange(e.target.value);

 number(e) {
        console.log('You\'ve pressed number ' + e.target.value);
        this.setState({
            number: e.target.value
        })
        this.props.onChange(e.target.value); // check this
    }

and by the way you can add this to the constructor: this.number = this.number.bind(this) and as a result you can do this (notice that we just wrote :'this.number'):

  <Button bsStyle="primary" value="1" onClick={this.number}>1</Button>
  <Button bsStyle="primary" value="2" onClick={this.number}>2</Button>
  <Button bsStyle="primary" value="3" onClick={this.number}>3</Button>
  <Button bsStyle="primary" value="4" onClick={this.number}>4</Button>
  <Button bsStyle="primary" value="5" onClick={this.number}>5</Button>
  <Button bsStyle="primary" value="6" onClick={this.number}>6</Button>
  <Button bsStyle="primary" value="7" onClick={this.number}>7</Button>
  <Button bsStyle="primary" value="8" onClick={this.number}>8</Button>
  <Button bsStyle="primary" value="9" onClick={this.number}>9</Button>

even better you can do this instead of repeating your self 9 times:

render() {
        let buttons = []
        for(var i =1; i <10; i++)
           buttons.push(<Button bsStyle="primary" value={i} onClick={this.number}>{i}</Button>)
        return (
            <div className="buttons">
                {buttons}
            </div>
        );
    }

本文标签: javascriptReact component props only changing after second onClick eventStack Overflow