0

I need to show the text according to the data value. By running the code, I want to see the 'Test1: 1' can be shown after I clicked the button, but I can't. Any method to make this happen?

Below is a sample sandbox link including the code. https://codesandbox.io/s/restless-wildflower-9pl09k?file=/src/Parent.js

export default function Parent(props) {
  const [data, setData] = useState(0);
  const onClick = () => {
    setData(1);
    console.log(data);
    setData(2);
  };
  return (
    <>
      <button onClick={onClick}> Click here </button>
      {data === 1 ? <div>Test1: {data}</div> : <div>Test2: {data}</div>}
    </>
  );
}
uu hu
  • 13
  • 3

2 Answers2

0

The reason the console.log(data) did not reflect the latest data is because of the React manages state. Calls to setState() are asynchronous, and if you want to rely on the new value of the state, the correct way is to pass a function of old state, returning the current state. ref. documentation

  • Got the reason, thankes! but the key point is I want to show 'Test1: 1', I changed the code in sandbox, but it still can't show me the 'Test1: 1',. could you help and point what the issue for my change? Actually, I don't care the prevData, I just want to change it to a new value and get the 'Test1: 1' in the page. – uu hu Mar 02 '22 at 14:05
  • What i mean is how to make the first setData's result make the render and show the 'Test1:1' – uu hu Mar 02 '22 at 14:10
  • Perhaps comment out the setState(2)? – Samarth Ramesh Mar 03 '22 at 04:12
0

The setState function returned by useState does not directly update the state. Instead it is used to send the value that React will use during the next asynchronous state update. console.log is an effect so if you want to see data logged every time it is changed, you can use React.useEffect. Run the code below and click the 0 button several times to see the state changes and effects in your browser.

function App() {
  const [data, setData] = React.useState(0)
  React.useEffect(_ => console.log("data", data), [data])
  return <button
    onClick={_ => setData(data + 1)}
    children={data}
  />
}

ReactDOM.render(<App/>, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Your comment talks about a network request example. Custom hooks can be designed to accommodate complex use cases and keep your components easy to write.

function App() {
  const [{fetching, error, data}, retry] = useAsync(_ => {
    return fetch("https://random-data-api.com/api/users/random_user")
      .then(res => res.json())
  }, [])
  if (fetching) return <pre>Loading...</pre>
  if (error) return <pre>Error: {error.message}</pre>
  return <div>
    <button onClick={retry} children="retry" />
    <pre>{JSON.stringify(data, null, 2)}</pre>
  </div>
}

function useAsync(f, deps) {
  const [state, setState] = React.useState({fetching: true})
  const [ts, setTs] = React.useState(Date.now())
  React.useEffect(_ => {
    f()
      .then(data => setState({fetching: false, data}))
      .catch(error => setState({fetching: false, error}))
  }, [...deps, ts])
  return [
    state,
    _ => {
      setState({fetching: true, error: null, data: null})
      setTs(Date.now())
    }
  ]
}

ReactDOM.render(<App/>, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
よつば
  • 467
  • 1
  • 8
  • Thanks for this input, but I think I may use the wrong sample, what I care is how to make the continues setstate can both have the render work, I just updated the sandbox: https://codesandbox.io/s/reverent-poincare-p9vdjk?file=/src/Parent.js From that, console.log can be replace by an network request, I just want to show loading status when the request not finished. Actually, I don't care about the previous data value, as I want to update it according to the request result. – uu hu Mar 02 '22 at 14:26
  • @uuhu I added another example. Give it a try. – よつば Mar 02 '22 at 14:55