0

The to value in my react app never updates.

I have the following code:

handleToChange(event) {
    this.setState({
        query: this.state.query,
        from: this.state.from,
        to: event.target.value,
        data: this.state.data,
        loading: this.state.loading,
    });
    console.log(event.target.value)
    this.triggerChange();
}

console.log(event.target.value) correctly returns the value, but the state is not updated. I know this as the app never updates the to value. The other values of the state update correctly and I use the same method to update them.

Here is the whole class. (the Handler class is the interface that makes the translation request to a server)

import React, {Component} from 'react';
import Handler from '../Handler.js';

class Translator extends Component {

    constructor() {
        super();

        this.state = {
            query: '', from: 'en', to: 'es', data: {}, loading: false
        };

        this.handleQueryChange = this.handleQueryChange.bind(this);
        this.handleFromChange = this.handleFromChange.bind(this);
        this.handleToChange = this.handleToChange.bind(this);

        this.triggerChange = this.triggerChange.bind(this);
        this.update = this.update.bind(this);
    }

    async update() {

        this.setState({
            query: this.state.query, from: this.state.from, to: this.state.to, data: this.state.data, loading: true,
        });

        let api = await Handler.get();

        this.setState({
            query: this.state.query, from: this.state.from, to: this.state.to, data: api, loading: false
        });
    }

    triggerChange() {
        Handler.put(this.state.query, this.state.from, this.state.to);
        this.update();
    }

    handleQueryChange(event) {
        this.setState({
            query: event.target.value,
            from: this.state.from,
            to: this.state.to,
            data: this.state.data,
            loading: this.state.loading,
        });
    }

    handleFromChange(event) {
        this.setState({
            query: this.state.query,
            from: event.target.value,
            to: this.state.to,
            data: this.state.data,
            loading: this.state.loading,
        });
        this.triggerChange();
    }

    handleToChange(event) {
        this.setState({
            query: this.state.query,
            from: this.state.from,
            to: event.target.value,
            data: this.state.data,
            loading: this.state.loading,
        });
        this.triggerChange();
    }


    render() {

        const error_message = (
            <div>
                <button data-toggle="collapse" data-target="#error" className="btn btn-outline-danger">Error</button>

                <div className="collapse" id="error">
                    Oops your query was invalid, this may be because of
                    <ul>
                        <li><b>The query is nonsense/ word does not exist in the language</b></li>
                        <li>There was a connection error to the api server</li>
                        <li>Exceeded quota
                            <ul>
                                <li>To prevent abuse, WordReference only allows a certain number of requests per IP</li>
                                <li>Please wait until the quota is reset</li>
                            </ul>
                        </li>
                        <li>Bugs: something may be wrong with the code.. my
                            bad &#175;&#92;&#95;&#40;&#12484;&#41;&#95;&#47;&#175;</li>
                    </ul>
                    You can always click the link to see the translations on WordReference
                </div>
            </div>
        );


        const loading_bar = (
            <div>
                <div className="progress" style={{height: 10}}>
                    <div className="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
                         aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style={{width: '100%'}}/>
                </div>
            </div>
        );

        let error = "";
        if (this.state.data['phrase'] === '{invalid}') {
            error = error_message;
        }

        let loading = "";
        if (this.state.loading) {
            loading = loading_bar;
        }


        return (
            <div>

                <div className="row">
                    <div className="col-sm">

                        <div className="input-box">
                            <div className="custom-control custom-control-inline">
                                From:
                                <select className="custom-select custom-select-sm" onChange={this.handleFromChange.bind(this)}
                                        defaultValue="en" disabled>
                                    <option value="en" selected>english</option>
                                    <option value="es">spanish</option>
                                    <option value="fr">french</option>
                                </select>

                                To:
                                <select className="custom-select custom-select-sm" onChange={this.handleToChange.bind(this)}
                                        defaultValue="es" disabled>
                                    <option value="en">english</option>
                                    <option value="es" selected>spanish</option>
                                    <option value="fr">french</option>
                                </select>

                            </div>
                            <br/><br/>

                            <div className="form-group">
                                <textarea className="form-control" id="" placeholder="Enter Text" rows="4"
                                          onChange={this.handleQueryChange}/>
                            </div>

                            <button onClick={this.triggerChange} className="btn btn-success">Go</button>

                        </div>

                    </div>

                    <div className="col-sm">
                        <div className="output-box">

                            <br/><br/>
                            <div className="card">
                                <div className="card-block">

                                    <div className="card-text">
                                        {this.state.data.phrase}
                                    </div>
                                    <br/><br/>

                                    <div className="card-footer">
                                        <a href={this.state.data.url} className="card-link">WordReference ></a>
                                    </div>

                                </div>

                            </div>

                        </div>
                    </div>

                </div>
                <br/>

                <div>
                    {loading}
                </div>

                <div className="error-box text-danger">
                    {error}
                </div>

            </div>
        );
    }

}

export default Translator;
  • 2
    In React `event` is not persistent, and `setState` is async (I believe). Try to use `event.persist()` as the first statement in function. Or save `event.target.value` in a local var and use it in `setState`. – Egor Stambakio Feb 03 '18 at 20:30
  • [Quoting this SO question](https://stackoverflow.com/q/17665489/463206) *As per "JavaScript The Definitive Guide" book this refers to the event target which seems to wrong. **event.currentTarget** seems more logical as event handlers are invoked as the method of the HTML element object.* – radarbob Feb 03 '18 at 20:52
  • need to see the whole class for this. but as was mentioned by wostex, setState() is asynchronous, so if you need to access values immediately then you need to use a Promise. in the code you posted, of course your console log would work because you have the value right there. but you may be incorrectly accessing state before the value is updated. – Jared Feb 03 '18 at 21:14
  • how you use the `handleToChange` function ? – Umair Ahmed Feb 03 '18 at 21:17
  • @UmairAhmed I use it to update a value in the state. This value holds a two letter language code. See updated code above – Ryuzaki Yagami Feb 07 '18 at 02:39
  • @Jared I posted it above. Let me know if you can figure it out. Thanks! – Ryuzaki Yagami Feb 07 '18 at 02:41

0 Answers0