LOUDKING
LOUDKING

Reputation: 321

ReactJS can only setState but cannot get state

in ReactJS I successfully passed props from parent to child components but when the callback function is called I notice that

  1. lines after this.setState() is not being executed.
  2. The value of this.state.* cannot be accessed at all.

Can anybody please help?

class RealTime extends Component {
    constructor() {
        super();
        this.state = {
            mode: true,
            marker_name: '',
            sensor_id: ''
        };
    }

    handleInputChange(event) {
        if(event.target.type === 'checkbox') {
            alert("checked = " + event.target.checked);
            this.setState({
                mode: event.target.checked
            });
            alert("yy");
        }
        else if(event.target.type === 'text') {
            alert("event.target.name = " + event.target.name + " value = " + event.target.value);
            this.setState({
                [event.target.name]: event.target.value
            });
        }
        else {
            alert("Unknown input type = " + event.target.type);
        }

        alert("xx");
    }

    handleSubmit(event) {
        event.preventDefault();
        alert('handleSubmit');
        alert("submitted marker_name=" + this.state.mode);
    }

    render() {
        return (
          <div className="animated fadeIn">
            <Row>
              <Col xs="12">
                <Card>
                    <CardHeader>
                        Real Time Number of Customers in Shops
                    </CardHeader>
                    <CardBlock className="card-body">
                        <MarkerForm mode={this.state.mode} marker_name={this.state.marker_name} sensor_id={this.state.sensor_id}
                                handleInputChange={this.handleInputChange} handleSubmit={this.handleSubmit}/>
                        <ConsoleEvent/>
                        <Canvas/>
                    </CardBlock>
                </Card>
              </Col>
            </Row>
          </div>
        )
    }
}

class MarkerForm extends Component {
    render() {
        return (
            <Form inline onSubmit={this.props.handleSubmit}>
                <FormGroup>
                  <Label className="switch switch-text switch-success switch-lg">
                    <Input type="checkbox" className="switch-input" checked={this.props.mode} onChange={this.props.handleInputChange}/>
                    <span className="switch-label" data-on="On" data-off="Off"></span>
                    <span className="switch-handle"></span>
                  </Label>
                </FormGroup>
                <FormGroup>
                    <Input type="text" placeholder="Marker Name" name="marker_name" value={this.props.marker_name} onChange={this.props.handleInputChange} required/>
                </FormGroup>
                <FormGroup>
                    <Input type="text" placeholder="Sensor ID" name="sensor_id" value={this.props.sensor_id} onChange={this.props.handleInputChange} required/>
                </FormGroup>
                <FormGroup className="form-actions">
                    <Button type="submit" color="primary" id="add-marker"><i className="fa fa-plus-square"></i> Add Marker</Button>
                    <Button type="button" color="danger" id="remove-marker"><i className="fa fa-minus-square"></i> Remove Marker</Button>
                </FormGroup>
            </Form>
        )
    }
   }

In code above,

alert("yy") is never being executed. Neither is alert("xx"). this is in handleInput.

And in handleSubmit() I can only see alert box 'handleSubmit' but not 'submitted marker_name='

Upvotes: 1

Views: 84

Answers (4)

Ariasa
Ariasa

Reputation: 1979

you need initialize the handle function inside custructor so you can use this: try this for bind:

constructor(props){
 this.state = {
        mode: true,
        marker_name: '',
        sensor_id: ''
 };
 this.handleInputChange = (event) => {
    if(event.target.type === 'checkbox') {
        alert("checked = " + event.target.checked);
        this.setState({
            mode: event.target.checked
        });
        alert("yy");
    }
    else if(event.target.type === 'text') {
        alert("event.target.name = " + event.target.name + " value = " + event.target.value);
        this.setState({
            [event.target.name]: event.target.value
        });
    }
    else {
        alert("Unknown input type = " + event.target.type);
    }

    alert("xx");
 };

 this.handleSubmit = (event) => {
    event.preventDefault();
    alert('handleSubmit');
    alert("submitted marker_name=" + this.state.mode);
 };
}

Upvotes: 0

Cruiser
Cruiser

Reputation: 1616

The issue is that this has a different context when you pass it to the component. You need to bind this to your function in the constructor:

class RealTime extends Component {
    constructor() {
        super();
        this.state = {
            mode: true,
            marker_name: '',
            sensor_id: ''
        };

    this.handleInputChange = this.handleInputChange.bind(this);
    // same for other functions
}

Upvotes: 0

Nocebo
Nocebo

Reputation: 2017

Try this:

 handleInputChange = (event) => {
        if(event.target.type === 'checkbox') {
            alert("checked = " + event.target.checked);
            this.setState({
                mode: event.target.checked
            });
            alert("yy");
        }
        else if(event.target.type === 'text') {
            alert("event.target.name = " + event.target.name + " value = " + event.target.value);
            this.setState({
                [event.target.name]: event.target.value
            });
        }
        else {
            alert("Unknown input type = " + event.target.type);
        }

        alert("xx");
    }

Use arrowfunctions to bind the function to your component and not loose the context of this. You can read more about them here: https://medium.com/@machnicki/handle-events-in-react-with-arrow-functions-ede88184bbb. Optionally you can bind the function in your constructor like the other answers suggested. However, if you have a couple of functions later on, you will realize that it is way smoother and cleaner to use arrow functions

Upvotes: 0

Ozgur
Ozgur

Reputation: 3766

You should bind the functions. It's because this has different context without binding:

constructor() {
    super();
    this.state = {
        mode: true,
        marker_name: '',
        sensor_id: ''
    };

    this.handleSubmit = this.handleSubmit.bind(this)
}

Upvotes: 2

Related Questions