Why React setState/useState does not update immediately

 https://linguinecode.com/post/why-react-setstate-usestate-does-not-update-immediately#the-answer-why

The answer: They’re just queues

React this.setState, and useState does not make changes directly to the state object.

React this.setState, and React.useState create queues for React core to update the state object of a React component.

React setState callback function after state changes

If you’re using a class component, you will have to usethis.setState() to update the state of a React component.


this.setState(state, callback);

The second parameter this.setState() accepts is the callback function, and that’s where you’ll want to add your side effects.

This callback function will get triggered when React state has finished updating.


this.setState(newStateObject, () => {
  // ... do some other actions
});

The example above uses the arrow function, but you can do it with a traditional function syntax.


this.setState(newStateObject, function() {
  // ... do some other actions
});

But what if you’re not using this.setState, and you’re using React.useState?

How do you perform an action after React.useState hook has triggered?

Use React useEffect after state has changed

React.useState doesn’t have accept callback function that gets called after React state has actually been modified.

To perform side effects after state has change, you must use the React.useEffect hook.


React.useEffect(callback, deps);

React.useEffect accepts a callback function to perform your side effects or actions, and it accepts a list of dependencies in the form of an array.

That hook function will only activate if the values in the list change.

Let’s take a look at an example


let s;

const Foo = () => {
  const [counter, setCounter] = React.useState(0);

  // Emmulate componentDidMount lifecycle
  React.useEffect(() => {
    s = setInterval(() => {
      setCounter(state => (state +1));
    }, 1000);
  }, []);

  // This is for counter state variable
  React.useEffect(() => {
    if (counter > 9) {
      clearInterval(s);
    }
  }, [counter]);

  return <span>{counter}</span>;
};

The first React.useEffect hook has an empty array. Since there are no dependencies, it only gets triggered once.

But in the second React.useEffect hook, I added my state variable as a dependency.

Any time my state variablecounter, changes in value, then the second React.useEffect function will re-activate. So it behaves like the React componentDidUpdate lifecycle.

function FormattedDate(props) {

  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;

}

class Clock extends React.Component {

  constructor(props) {

    super(props);

    this.state = {date: new Date()};

  }


  componentDidMount() {

    this.timerID = setInterval(

      () => this.tick(),

      1000

    );

  }


  componentWillUnmount() {

    clearInterval(this.timerID);

  }


  tick() {

    this.setState({

      date: new Date()

    });

  }


  render() {

    return (

      <div>

        <h1>Hello, world!</h1>

        <FormattedDate date={this.state.date} />

      </div>

    );

  }

}


function App() {

  return (

    <div>

      <Clock />

      <Clock />

      <Clock />

    </div>

  );

}


ReactDOM.render(<App />, document.getElementById('root'));


Không có nhận xét nào:

StaticImage

  import React , { useEffect , useRef } from "react" import { StaticImage } from "gatsby-plugin-image" impor...