0

how to get result state correctly after update using setState. here is code example i got from which is similar with my code Why react hook value is not updated in async function? . but still there is no solution answer for that problem. many helps will be helpful. Thank you

import React, { Component, useState } from "react";
import { render } from "react-dom";

function App() {
 const [value, setValue] = useState('old');

 const run = async() => {
  setValue('new')
  const data = await wait(500)
  console.log(value)
 }

return (
  <button onClick={run}>
    Run
  </button>
);
}

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

 function wait(ms) {
   return new Promise(resolve => setTimeout(resolve, ms))
 }

2 Answers2

0

You need to use useEfect like :

     React.useEffect(()=>{
      console.log(value)
    }, [value])

Simon G
  • 16
  • 1
  • 3
  • This doesn't really answer the question. – Jared Smith Mar 05 '21 at 19:40
  • It will helpful if there is a parent component called in the child component. and the child component makes a transaction to parent component so there is data sent to parent. for example we make button global. then we set button global to other component. the problem is when button global is clicked or triger by child component. it willn't run or render the button global. because button global is rendered in parent component so in child component is not rendered. my solution is we have set state hooks in trigered button global and set use effect to get the result of trigered. hope its help – Adam Abdullah Mar 17 '21 at 08:30
0

You don't control state. React controls. After you asked React to change stored state you should not assume when it will be updated. Maybe next millisecond, maybe next year (I'm exaggerating just to make a point). Your component always renders current state, so when React will, eventually change state value, it will rerun your component. In a single run you place state value into variable that is not updated by React, since it is local. It is closured inside effect and even if React wanted, it can't assign new value to variable it does not know about.

Since your component is pure (not really, but let's stick to this terminology for simplicity), you don't own side effects. You can politely ask React to perform some side effects on some events - either DOM events (like onClick where you put side effect in form of handler), or on each render with useEffect hook. With useEffect you can limit when react will actually run your side effect. With dependencies array you can say "Hey, React, can you please run this side effect on initial render and when this values are changed".

Putting it together, to track that state value changed you need one more useEffect hook, where you will be able to say with 100% certainty that state value changed. It will look like this:

function App() {
  const [value, setValue] = useState("old");

  useEffect(
    function () {
      console.log(value);
    },
    [value]
  );
  const run = async () => {
    setValue("new");
    const data = await wait(500);
    console.log(value);
  };

  return <button onClick={run}>Run</button>;
}

But sometimes it is also just a part of solution. Sometimes you want to run side effect only when dependency value is "new" and not run it when it is "old". In this case you can add additional check inside your effect and make an early return if it is not value you are looking for:

function App() {
  const [value, setValue] = useState("old");

  useEffect(
    function () {
      if (value !== "new") return;
      console.log(value);
    },
    [value]
  );
  const run = async () => {
    setValue("new");
    const data = await wait(500);
    console.log(value);
  };

  return <button onClick={run}>Run</button>;
}

While it is almost sufficient, often it is better to put state and tied to said state effects in custom hook, or use some dedicated "state management" solution where side effects are first class citizens.

Mr. Hedgehog
  • 2,644
  • 1
  • 14
  • 18
  • it is true that the component will always render the current state. indeed the best solution is to use useEffect as a callback if we want to add side effect after changing state. is that correct ? – Adam Abdullah Mar 06 '21 at 04:20
  • I wouldn't call it callback, but yes, it is correct. – Mr. Hedgehog Mar 06 '21 at 07:56
  • sometimes using the settimeout also works – Adam Abdullah Mar 17 '21 at 00:49
  • `setTimeout` works when you have reference to some mutable variable and mutate it (primitives are not mutable). But mutating state or props inside component is forbidden, so you have to ask react to do it for you. When you use refs, however, you are free to do whatever you want with them, but only as a side effect, and side effects should also run by react, either in effect hook, or in event handler – Mr. Hedgehog Mar 17 '21 at 01:11