React state not retuning the latest value of state

Tags: ,



The value of this.state.topText and this.state.bottomText is always one change behind. E.g if I type 1234 in topText’s input box, the value of this.state.topText would be 123. The react docs say to fix asynchronous updates we should use the form of setState() that accepts a function rather than an object. I have done that and the value of setState is still lagging. How do I fix the setState() in handleChange()?

App.js

import React from "react";
import MemeGenerator from "./MemeGenerator"
import "./styles.css";

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      topText:"",
      bottomText: "",
      imgs: [],
      imgUrl:""
    };
    this.handleChange=this.handleChange.bind(this)
    this.handleClick=this.handleClick.bind(this)
  }

  handleChange(event) {
    const {name, value} = event.target
    this.setState((prevstate) => ({
      ...prevstate,
      [name]: value
    }));
    document.getElementById('tt').innerHTML=this.state.topText;
    document.getElementById('bt').innerHTML=this.state.bottomText;

  }

  handleClick(target){
    const imgNum=this.state.imgs.length;
    const randNum=Math.floor(Math.random()*imgNum)
    this.setState((prevState)=>{
      return {imgUrl: prevState.imgs[randNum].url }
    })

  }
  
  componentDidMount(){
    fetch('https://api.imgflip.com/get_memes')
    .then((response)=> response.json())
    .then((data)=>{
      const randImg=data.data.memes
      this.setState(()=>{
        return{imgs: randImg}
      })
    })
  }

  render() {
    return (
      <MemeGenerator 
        handleChange={this.handleChange}
        handleClick={this.handleClick} 
        topText={this.state.topText}
        bottomText={this.state.bottomText}
        imgUrl={this.state.imgUrl}
        
      />
    );
  }
}

export default App;


MemeGenerator.js

import React from "react"

function MemeGenerator(props){
  return(
    <div className="App">
      <h1>Meme Generator</h1>
      <input 
        type="text"
        name="topText"
        value={props.topText}
        onChange={(event)=>props.handleChange(event)}
      />

      <input 
        type="text"
        value={props.bottomText}
        name="bottomText"
        onChange={(event)=>props.handleChange(event)}
      />
      
      <button onClick={(event)=>props.handleClick(event.target)}>Gen</button>

      <img 
        src={props.imgUrl} 
        alt="" 
        width="300"
      />
      
      <p id="tt"></p>
      <p id="bt"></p>
  </div>
  )
}

export default MemeGenerator

Answer

setState accepts a callback as a second param which will be executed right after the state change.

handleChange(event) {
    const {name, value} = event.target
    this.setState({ [name]: value }, () => {
        document.getElementById('tt').innerHTML=this.state.topText;
        document.getElementById('bt').innerHTML=this.state.bottomText;
    });
}

Please check the below:

https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296 https://upmostly.com/tutorials/how-to-use-the-setstate-callback-in-react



Source: stackoverflow