简体   繁体   中英

React component not rendering response of Axios request

I have a form input that allows a user to input text and submit it. Once the submit button is hit, I validate the input by checking if it's empty or longer than 120 characters. I also pass the input to an API that checks the grammar and will fix it automatically.

Right now, my response from Axios is there (I can console.log it), but in my database and other places it is the uncorrected versions.


import React, { Component } from "react";
import axios from "axios";


class CreateText extends Component {

    constructor() {
        super();
        this.state = {
            textInput: "",
        };

    }

    checkGrammar = async () => {
        let response = await axios({
            method: 'get',
            url: 'https:/an-api-endpoint/',
            params: {
                apiKey: '',
                userId: '',
                content: this.state.textInput,
                format: 'json'
            }
        });
        const { data } = await response;
        // if I console log after this, I see it in my state as the correct version
        this.setState({
            textInput: data['corrected-content'] ? data['corrected-content'] : this.state.textInput
        });
    }


    handleInput = event => {
        this.setState({
            textInput: event.target.value
        });
    }

    handleSubmit = event => {
        event.preventDefault();

        this.validateInput();
        if (this.state.textInput) { 
          // push to db and clear the text state
            this.setState({
                textInput: ""
            });
        }
        else {
            console.log('Failed handle submit');
        }

    }

    validateInput = () => {
        if (this.state.textInput !== "") {
            if (this.state.textInput.length < 120) {
                this.checkGrammar();
            }
            else {
                console.log('Failed validate input');
                return; // TODO: Error handling.
            }
        }
    }

    render() {
        return (
            <div className="input">
                <form onSubmit={this.handleSubmit}>
                    <label htmlFor="textInput"></label>
                    <input
                        id="textInput"
                        type="text"
                        value={this.state.textInput}
                        onChange={this.handleInput}
                        placeholder="insert text"
                    />
                    <button className="textButton" type="submit">Submit Text</button>
                </form>
            </div>
        )
    }
}

export default CreateText;

I try to setState to textInput for the response using async/await, I tried other methods, but it seems when I hit the Submit/ handleSubmit , it calls out to the API, but continues and submits, then gets the corrected input. I can see it on my text input afterwards which shouldn't happen since after submitting, the state text is cleared. It leads me to believe that it gets added, cleared, then axios data comes back and fills in the state (too late.)

Am I doing something blatantly wrong here? I'm confused about the axios promise and thought I could handle it with setState and async/await.

Thanks.

You can move the textInput conditional logic in the checkGrammar function like this to avoid asynchronous race conditions:

import React, { Component } from "react";
import axios from "axios";


class CreateText extends Component {

    constructor() {
        super();
        this.state = {
            textInput: "",
        };

    }

    checkGrammar = async () => {
        let response = await axios({
            method: 'get',
            url: 'https:/an-api-endpoint/',
            params: {
                apiKey: '',
                userId: '',
                content: this.state.textInput,
                format: 'json'
            }
        });
        const { data } = response;
        // if I console log after this, I see it in my state as the correct version
        const textInput = data['corrected-content'] ? data['corrected-content'] : this.state.textInput;
        if ( textInput ) { 
            // push to db and clear the text state
              this.setState({
                  textInput: ""
              });
          }
          else {
              console.log('Failed handle submit');
          }

    }


    handleInput = event => {
        this.setState({
            textInput: event.target.value
        });
    }

    handleSubmit = event => {
        event.preventDefault();
        this.validateInput();
    }

    validateInput = () => {
        if (this.state.textInput !== "") {
            if (this.state.textInput.length < 120) {
                this.checkGrammar();
            }
            else {
                console.log('Failed validate input');
                return; // TODO: Error handling.
            }
        }
    }

    render() {
        return (
            <div className="input">
                <form onSubmit={this.handleSubmit}>
                    <label htmlFor="textInput"></label>
                    <input
                        id="textInput"
                        type="text"
                        value={this.state.textInput}
                        onChange={this.handleInput}
                        placeholder="insert text"
                    />
                    <button className="textButton" type="submit">Submit Text</button>
                </form>
            </div>
        )
    }
}

export default CreateText;

Codesandbox

Suggestion: You should definitely read more about how async functions (like setState ) work, and try to understand async/await, since these kind of issues will come forth on a daily basis in JavaScript/React.

If you intend to work with React, you must understand the inner workings of the asynchronous setState method, and learn about the callback version of this method. A good starting point is this StackOverflow post .

From the post, this is probably the most crucial point: " setState works in an asynchronous way. That means after calling setState the this.state variable is not immediately changed. so if you want to perform an action immediately after setting state on a state variable and then return a result, a callback will be useful "

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM