2

I am using reactjs in my application . The currid_s is set to value -1 initially.. later after button click it is set to 2 but the timer doesnot show the updated value in the Console. Why? Here is the code

 
import React, { useState, useEffect } from "react";

export default function App() {
  const [currid_s, setcurrid_s] = React.useState(-1);
  const handless = () => {
    console.log("yess");
    setcurrid_s(2);
  };

  useEffect(() => {
    console.log(currid_s, "yes");
    getPosts();

    const interval = setInterval(() => {
      getPosts();
    }, 2000);

    return () => clearInterval(interval);
  }, []);

  // const all_pooo=()=>{
  //   console.log(curr,"dddd")
  // }
  const getPosts = async () => {
    console.log(currid_s);
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <button onClick={handless}>gggg</button>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

Here is the link to code sandbox https://codesandbox.io/embed/beautiful-ardinghelli-dg1r4?file=/src/App.js&codemirror=1

Rocky
  • 29
  • 6
  • 1
    Callback function of the interval has a closure over the value of `currid_s` that was in-effect when the timer interval set. You need to set a new interval whenever `currid_s` is updated. You can do this by adding `currid_s` in the dependency array of the `useEffect` hook. – Yousaf May 22 '21 at 16:35
  • @Yousaf but how is the interval affecting currid_s value? – Tushar Shahi May 22 '21 at 16:44
  • Can u change in the codesandbox @Yousaf please? – Rocky May 22 '21 at 16:45
  • It looks to me like you are complicating things in your code. Why have `setInterval` run with `onClick` when you can just use `useEffect` to call `getPost` based on changes made to `currid_s` – Udendu Abasili May 22 '21 at 16:47
  • 1
    [Demo](https://codesandbox.io/s/sleepy-hoover-lnduq?file=/src/App.js) – Yousaf May 22 '21 at 16:50
  • @UdenduAbasili the useEffect is used as componentdidmount so that the getposts() function runs every two seconds to get backend stuff... Now when I click on the button the state changes for currid_s but it's not updating on the getposts function? If you have any alternatives to this please tell me those – Rocky May 22 '21 at 16:51
  • 2
    @TusharShahi what do you mean? `setInterval` is not changing its value; it just calls a function, i.e. `getPosts`, that logs the value of `currid_s`. – Yousaf May 22 '21 at 16:51
  • @Rocky I know what `useEffect` is. I am say that instead of using `setInterval` to call your backend, why not call the backend only when `currid_s` changes. – Udendu Abasili May 22 '21 at 16:55
  • @Yousaf I just checked your code ... I have many react hooks should I include all of them in it? – Rocky May 22 '21 at 16:59
  • Please look at this. https://stackoverflow.com/questions/53024496/state-not-updating-when-using-react-state-hook-within-setinterval – Zhang TianYu May 22 '21 at 17:00
  • I get data from backend... After clicking on the data which came from backend on ui the state changes and should console in getposts @Udendu Abasili – Rocky May 22 '21 at 17:07
  • @Yousaf sorry. I missed that. Yes you are correct. – Tushar Shahi May 22 '21 at 17:16

2 Answers2

2

You cannot get your new state value inside your setInterval because you're storing an old version of getPosts inside your interval callback function.

What happens is when currid_s updates, your App component rerenders, and a new getPosts function is initialized containing the new value. However, setInterval callback function stores a reference to an old getPosts function containing the old value. This old getPosts function would print the copy of the old currid_s value that was assigned upon mounting of the App component. Javascript does not support referencing of primitives, that's why your old getPosts function does not have the new value.

If you want to print your currid_s whenever it updates, just do this:

useEffect(() => {
  console.log(currid_s)
}, [currid_s])
khayliang
  • 130
  • 1
  • 5
2

You can change currid_s from a useState() to a useRef() so that its value is accessible from the closure that the setInterval callback captures:

const { useRef, useEffect } = React;

function App() {
  const currid_s = useRef(-1);
  const handless = () => {
    currid_s.current = 2;
  };

  useEffect(() => {
    const getPosts = () => {
      console.log(currid_s.current);
    };

    getPosts();

    const interval = setInterval(() => {
      getPosts();
    }, 2000);

    return () => {
      clearInterval(interval);
    };
  }, []);
  
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <button onClick={handless}>Click me</button>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153