1

Having trouble getting changes to persist with async function when called from an onClick event handler. I have the functions I am calling:

        retrieveData = async () =>{
        try {
            console.log(1)
            console.log(this.state.ID)
            const url = this.baseUrl + "api/" + this.state.ID
            let response = await fetch(url, {mode: "cors"})
            const data = await response.text()
            this.setState({testVal: data})
            console.log(data)
        } catch (e) {
            console.error(e)
        }
    }

The above function works when I put its contents in componentDidMount() and hardcode the state ID. But not when I try to call the retrieved data function like so, so I assume the following snippet is where the error is.

    render() {
        return(
            <div>
                <div>
                    <form>
                        <label>
                            ID:
                            <input type="text" onChange={e => this.setState({ID: e.target.value})}/>
                        </label>
                        <input type="submit" onClick={async () =>{await this.retrieveData();}}/>
                    </form>
                </div>
                <div>
                    {this.state.ID}
                    {this.state.testVal}
                </div>
            </div>
        );
    }

Im fairly new to reactJS, so I am sure it is something simple. When I click the submit button, I see the console spit out the 1, and then the ID I had just entered, and then both immediately disappear. When I check to see if the fecth is happening, I dont see any calls to the api like when I tested with a hardcoded url with componentDidMount(), but I want to be able to take user input, just a little unsure how to. I believe I have checked just about every SO question I can find on this, so I really am lost. If more info is needed please let me know, thank you.

5
  • I'd recommend to add a try/catch to each async operation and check if any errors are occurring. Adding {mode: "cors"} will not resolve various CORS error from the server you are making requests to. Also this could be failing at the request level, at the .text() if it's not text, but application/json Commented May 5, 2020 at 17:44
  • @AlexanderStaroselsky I went ahead and added the try catch, I do not get any errors, from my perspective, it seems that the fetch never even attempts. Commented May 5, 2020 at 18:18
  • You are not seeing any requests in the network tab of your developer tools? Commented May 5, 2020 at 18:29
  • @AlexanderStaroselsky I rechecked, I needed to try and take a picture because it happens so fast. It does make the request, but only for a split second, it appears on my network tab, then immediately disappears. Commented May 5, 2020 at 18:31
  • I’ll submit an answer in a few I know what the issue is. Commented May 5, 2020 at 18:43

3 Answers 3

2

Thank you all for your help, this is the following change I made.

I changed

<input type="submit" onClick={async () =>{await this.retrieveData();}}/>

To this

<input type="button" value= "submit" onClick={e=>this.retrieveData(e)}/>

And now it works perfectly, so no issues with that. Thank you again.

Sign up to request clarification or add additional context in comments.

Comments

0

Please check this example where you call api using fetch after clicking a button.

import React, {Component} from "react";

class FetchExample extends React.Component {
    state = {
        isLoading: false,
        questions: [],
        error: null
    };

    fetchQuestions = () => {
        fetch(`https://opentdb.com/api.php?amount=10&difficulty=hard&type=boolean`,)
            .then(response => {
                    if (response.status !== 200) {
                        console.log('There was a problem. Status Code: ' + response.status);
                        return;
                    }
                    response.json().then(data => {
                        console.log(data);
                        this.setState({
                            questions: data,
                            isLoading: false
                        })
                    });
                }
            )
            .catch(function (error) {
                console.log('Error: ', error);
                this.setState({error, isLoading: false})
            });
    };

    render() {
        const {isLoading, questions, error} = this.state;
        return (
            <React.Fragment>
                <h1>Random Question</h1>
                <button onClick={this.fetchQuestions}>Click for calling API using fetch</button>
                {error ? <p>{error.message}</p> : null}

                {!isLoading && questions.results ? (
                    questions.results.map((questions, index) => {    //something right here
                        //is erroring
                        const {question, category, type, difficulty} = questions;
                        return (
                            <div key={index}>
                                <p>Question: {question}</p>
                                <p>Question Type: {type}</p>
                                <p>Difficulty: {difficulty}</p>
                                <hr/>
                            </div>
                        );
                    })
                ) : isLoading ? (
                    <h3>Loading...</h3>
                ) : null}
            </React.Fragment>
        );
    }
}

export default FetchExample;

Comments

0

The issue is that the form submit handler is being executed and that is refreshing the page as there is not prevent default to catch that submit event. To resolve this I'd recommend to move the handler from the input button to the form handler. You would also need to prevent the form submit from occurring which you can achieve via the form handler event and preventDefault(). Otherwise the page would refresh when you submit the form.

handleChange = (e) => {
  this.setState({ ID: e.target.value });
}

retrieveData = async (e) =>{
  e.preventDefault();

  try {
      console.log(1)
      console.log(this.state.ID)
      const url = this.baseUrl + "api/" + this.state.ID
      let response = await fetch(url, {mode: "cors"})
      const data = await response.text()
      this.setState({testVal: data})
      console.log(data)
    } catch (e) {
      console.error(e)
    }
}

render() {
  return(
      <div>
          <div>
              <form onSubmit={this.retrieveData}>
                  <label>
                      ID:
                      <input type="text" handleChange={this.handleChange} />
                  </label>
                  <button type="submit">Submit</button>
              </form>
          </div>
          <div>
              {this.state.ID}
              {this.state.testVal}
          </div>
      </div>
  );
}

Notice I removed the click handler from the input submit control, because I'd imagine that two events were occurring a click on the button then also a submit on the form. While the input submit control click was occurring, the submit on the form itself was not being prevent and causing the page to refresh and preventing the HTTP request from completing.

Hopefully that helps!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.