0

this is not a duplicate because i tried to add an updater function and it didn't work this is the code i have

const [counter, setCounter] = useState(0);
    useEffect(()=>
    {
      const fetchSessions =async ()=>
        {
            instance.events.sessionCreated({fromBlock:0}).on("data",async (evt)=>{ handleSessionCreatd(evt)})
        }
        fetchSessions();
    },[]);
    
    
    const handleSessionCreatd =async (event)=>
    {
        let index = event.returnValues.id -1;
        let session = await instance.methods.sessions(index).call();
        console.log("index is at:",index);
        setCounter(counter => counter+1);
        //setCounter(prev=>index);
        console.log("counter is at",counter);
    }

i wanted to execute a callback to newly created sessions, so i put it inside useEffect() with empty array to register my callback only once (since the eventListner keeps updating automatically), the value of index updates successfully, however the value of my counter does not update.

  • how do i update my counter?

  • even though im using useEffect() with empty array, the output is a bit wierd in that it prints the execution twice:

    index is at 0

    counter is at 0

    index is at 1

    counter is at 0

    .

    .

    .

    index is at 10

    counter is at 0

then it prints the previous list another time starting from 0 (completely the same list, counter still does not update), what causes this behavior?

ps: the event is from web3.js. and even if i uncomment the second setState it still does not increment (i thought maybe its somehow still taking the catched value from the closure)

ezio
  • 359
  • 2
  • 13
  • Move fetchSessions declaration outside useEffect. You dont want to declare function on every render. Leave only function exporession `fetchSessions()` inside – CptSosen Jun 23 '22 at 15:41
  • @CptSosen Wouldn't that still declare the function on every render? Unless you mean, use `useCallback` to avoid that? – nullptr Jun 23 '22 at 15:49
  • `setState` is async. It will not update the current value immediately. The new value will only be set during the next render of the component. It will never change during the same render. – trixn Jun 23 '22 at 15:50
  • @nullptr The function will be declared no matter where it is placed inside of the component. For it to not be redeclared you would need to declare it entirely outside of the component. `useCallback` will just prevent it from being used and possibly passed as a prop to any children if none of the dependencies changed as `useCallback` caches the function and only updates the cache if one of the objects in the dependency list changed. – trixn Jun 23 '22 at 15:56
  • @trixn it will prevent React from creating new instance of the same function, it has nothing to do with preventing function from being used as prop – CptSosen Jun 23 '22 at 15:59
  • @CptSosen Functions are created by the javascript engine. This has nothing to do with react. Whenever the component (which is just a javascript function) will be called, which is on every render, the functions declared inside of it will be re-created. This is a javascript issue, not a react issue. This is the sole purpose of `useCallback`. It prevents re-created functions to be used and instead caches them so they will not be passed as props if their dependencies didn't change (because that may come with a big performance penalty). – trixn Jun 23 '22 at 16:18
  • @trixn it is exacly as i wrote, if you have trouble understanding `useCallback` hook purpose please read the docs. It has everyting to do with React and how React works – CptSosen Jun 23 '22 at 19:10
  • @CptSosen I fully understand the `useCallback` hook and it exactly addresses the problem I described. Inner functions declared inside of functions are re-created every time the outer function is called and to avoid passing a new function as a prop to children every time a component renders the `useCallback` hook memorizes a function until the dependencies provided through the dependencies change. That's the whole purpose. You have a misconception about what is the scope of react vs the scope of the javascript compiler. A function is only not recreated if it is entirely outside of a component. – trixn Jun 23 '22 at 22:34
  • @CptSosen "it will prevent React from creating new instance of the same function"... This is entirely wrong. React does not create instances of functions. the javascript engine does that. An inner function scoped in the component function will always be re-created when the component function is called (which is on every render). React can't "prevent" that in any way. The purpose of `useCallback` is to memorize a once created function until the dependency array changes to avoid passing new functions to children unnecessarily. The function will still be created no matter what. – trixn Jun 23 '22 at 22:54

3 Answers3

0

setState is async, it means that console.log can't display the value before it has changed

CptSosen
  • 160
  • 1
  • 13
0

As I can see you are passing handler only once on initialization, and like that counter value inside handler will be retrieved from the closure. Since on initialization counter is 0, then in each log you will print that same 0 from closure which was constructed on that first(and only) time you passed event handler. Try to log outside of the event handler and see what is the value of counter. If you do need counter in event handler then you will need to include some dependencies in useEffect in order to reconstruct that closure you are reading from.

Milos Pavlovic
  • 1,355
  • 1
  • 2
  • 7
  • but why does it get executed twice? that will make counter value 20 instead of the same as index which is 10 !! – ezio Jun 23 '22 at 16:09
0

The solution was to Disable React.strictMode in index.js (just delete the line), moreover since setState is async, the execution moves to console log without necessarily executing setState therefore it outputs old values. so in order to get the final value simply console.log it outisde of useEffect, it will also give you a clue on how many times React re-renders and its optimization techniques

ezio
  • 359
  • 2
  • 13