How to use async await inside an event?

Viewed 846

This is the code for the intro page for my game. It has a submit button and textbox for username input. When user writes his name down and hit the submit button, the code post the name into a json file, then get all the data from the json file to send it to a leaderboard. That's working. But it dont get the last posted username. I tried to add a async await function to getUserInfo(), (console.log("userinfo: " + this.state.usersInfo) shows everyobject when i add async await) but the game page does not show up and i get a weird error on console: Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the method `preventDefault` on a released/nullified synthetic event. This is a no-op function. If you must keep the original synthetic event around, use event.persist(). I did try using event.persist() already but game page still doesnt show up. Any help?

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      page: "game",
      showInicio: false,
      userInput:"",
      usersInfo:[],
      dataPosted: false,
      head:[],
      isNew: true,
    };
    //function needs to be bound to be used in child component (NavBar.js)
    this.changePage = this.changePage.bind(this);

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

  changePage(page) {

    this.setState({
      page

    });
  }

  handleChange(event) {
    this.setState({userInput: event.target.value});

  }

  async handleSubmit(event) {
    this.postUserInfo(); 
    await this.getUserInfo();
    console.log("userinfo: " + this.state.usersInfo)
    alert('Username was submitted: ' + this.state.userInput);
    event.preventDefault();
    this.setState({  
      showInicio: !this.state.showInicio 
 }); 

  }


   postUserInfo(){
    fetch("http://localhost:8080/api/users" , {
      method: "post" ,
      mode: "cors",
      headers: {
        "Content-type": "application/json",
      },
      body:JSON.stringify({username:this.state.userInput,bestattempts:0, besttime:0 })
    })

    .then((res) => res.json()) 
    .then((data => {
      console.log(data);  
      this.setState({ dataPosted: true });
    }))
    .catch((error) => {
    console.log(error);
  });
  } 

  async getUserInfo() {
    return fetch("http://localhost:8080/api/users" , {mode: "cors"})
    .then((res) => res.json())
    .then((data => {
      this.setState({ usersInfo: data})

    const _head = {
      id: "ID",
      username: "Username",
      bestattempts: "Best Attempts", 
      besttime: "Best Time",
    }
    this.setState({head:_head})}))
  }     


  render() {
    if (this.state.showInicio === false){
    return (
      <div>
      <div className="inicio">  
        <h1> Memory game </h1> 
      </div>
      <div className="iniciodentro">
        <form onSubmit={this.handleSubmit}>
        <label>
          Enter your username:
        <input type="text" value={this.state.userInput} onChange={this.handleChange} required/>
        </label>
        <input type="submit" value="Submit" />
      </form>
      </div> 
      </div>
     );
    }else{
    const { page } = this.state;
    return (
      <div className="App">
        <NavBar page={page} changePage={this.changePage} />
        <div className="App-header">
          {page === "game" && <Game dataPosted={this.state.dataPosted} username = {this.state.userInput} isNew={this.state.isNew}/>}
          {page === "leaderboard" && <LeaderBoard usersInfo={this.state.usersInfo} head={this.state.head}/>}
        </div>
      </div>
    );
  }
}
}

export default App;

1 Answers

To put it simply, I would suggest I suggest turning your handleSubmit into this:

handleSubmit(event) {
    event.preventDefault();

    this.postUserInfo().then(()=>{

        return this.getUserInfo();

    }).then(()=>{

        console.log("userinfo: " + this.state.usersInfo)
        alert('Username was submitted: ' + this.state.userInput);
        this.setState({
            showInicio: !this.state.showInicio
        });

    });
}

and do this in your postUserInfo and getUserInfo methods:

postUserInfo(){
    return fetch("http://localhost:8080/api/users", {
        method: "post",
        mode: "cors",
        headers: {
            "Content-type": "application/json",
        },
        body: JSON.stringify({ username: this.state.userInput, bestattempts: 0, besttime: 0 })
    })
    .then((res) => res.json())
    .then(data => {
        console.log(data);
        this.setState({ dataPosted: true });
    })
    .catch((error) => {
        console.log(error);
    })

}
getUserInfo() {
    return fetch("http://localhost:8080/api/users", { mode: "cors" })
        .then((res) => res.json())
        .then(data => { //you had a syntax mistake here: (data
            this.setState({ usersInfo: data })

            const _head = {
                id: "ID",
                username: "Username",
                bestattempts: "Best Attempts",
                besttime: "Best Time",
            }
            this.setState({ head: _head })
        })
}

there's no need to use async/await as the fetch API already uses promises.

The reason you were getting the weird error may have been because you were trying to preventDefault() inside of an async function. is because preventDefault is being executed AFTER the first await

Thanks to Bravo for clarifying.

Related