Can't see state inside method helper function using hooksReact js onClick can't pass value to methodmapStateToProps() in Connect(EquipmentMetadata) must return a plain object. Instead received undefinedCan I set state inside a useEffect hookWhy can't React Hooks be called inside loops or nested function?How does redux state changes but component doesn'tFunction CollectionReference.add() requires its first argument to be of type object, but it was: undefinedReact Hooks - function inside function component passed as prop can't access stateReact Hooks: Lazy Loading Breaks useLayoutEffect?Hooks and immutable stateReact hooks function component prevent re-render on state update

How to perform Login Authentication at the client-side?

Singing along to guitar chords (harmony)

Mount a folder with a space on Linux

Is adding a new player (or players) a DM decision, or a group decision?

Inverse-quotes-quine

What is the line crossing the Pacific Ocean that is shown on maps?

Fedora boot screen shows both Fedora logo and Lenovo logo. Why and How?

Why aren't (poly-)cotton tents more popular?

Is there a maximum distance from a planet that a moon can orbit?

Calculating the partial sum of a expl3 sequence

How risky is real estate?

A player is constantly pestering me about rules, what do I do as a DM?

Fitting a mixture of two normal distributions for a data set?

Is there any set of 2-6 notes that doesn't have a chord name?

What can I do to find new work while my workplace is closed due to an accidental death?

Why do some games show lights shine through walls?

How many codes are possible?

How could mana leakage be dangerous to a elf?

Find smallest index that is identical to the value in an array

How often can a PC check with passive perception during a combat turn?

Does Marvel have an equivalent of the Green Lantern?

Why isn’t the tax system continuous rather than bracketed?

Should I hide continue button until tasks are completed?

What would Earth look like at night in medieval times?



Can't see state inside method helper function using hooks


React js onClick can't pass value to methodmapStateToProps() in Connect(EquipmentMetadata) must return a plain object. Instead received undefinedCan I set state inside a useEffect hookWhy can't React Hooks be called inside loops or nested function?How does redux state changes but component doesn'tFunction CollectionReference.add() requires its first argument to be of type object, but it was: undefinedReact Hooks - function inside function component passed as prop can't access stateReact Hooks: Lazy Loading Breaks useLayoutEffect?Hooks and immutable stateReact hooks function component prevent re-render on state update






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








3















I cannot see the updated state inside of the helper method I'm using. All those worked in the class-based component, but it seems to be not the same when using hooks. Check out my comments.



import React, useEffect, useRef, useState from 'react';
import createPortal from 'react-dom';
import ReactPlayer from 'react-player';

import VIMEO_URL from '../../consts/urls';
import storage from '../../utils/localStorage';

const STORAGE_VIDEOS_DATA_KEY = 'VIDEOS_DATA';

import './VideoItem.scss';


const VideoItem = ( vimeoId ) =>
useEffect(() =>
window.addEventListener(
'beforeunload',
saveStateToLocalStorage
);

return () =>
window.removeEventListener(
'beforeunload',
saveStateToLocalStorage
);

saveStateToLocalStorage();
;
, []);


const [ videoProgress, setVideoProgress ] = useState(0);

const saveStateToLocalStorage = () =>
const videosPlayedDuration =
[vimeoId]: videoProgress, // here I'm not getting updated videoProgress state, only default value
;

// here I will save videosPlayedDuration to the storage
;

return createPortal(
<div className="video-modal-background" onClick=onVideoClose>
<div className="video-modal-window">
<ReactPlayer
playing=true
url=VIMEO_URL + vimeoId
onProgress=videoProgress => setVideoProgress(videoProgress.playedSeconds) // here I'm setting state
/>
</div>
</div>,
document.getElementById('modal-root')
);
;

export default VideoItem;


So the as you can see I'm trying to use updated state but all I'm getting there is 0 as a default state.










share|improve this question



















  • 2





    That's because your useEffect hook is only run once after the initial render, so the saveStateToLocalStorage reference inside of the function given to it will always be a reference to the saveStateToLocalStorage of the initial render.

    – Tholle
    Mar 25 at 10:40

















3















I cannot see the updated state inside of the helper method I'm using. All those worked in the class-based component, but it seems to be not the same when using hooks. Check out my comments.



import React, useEffect, useRef, useState from 'react';
import createPortal from 'react-dom';
import ReactPlayer from 'react-player';

import VIMEO_URL from '../../consts/urls';
import storage from '../../utils/localStorage';

const STORAGE_VIDEOS_DATA_KEY = 'VIDEOS_DATA';

import './VideoItem.scss';


const VideoItem = ( vimeoId ) =>
useEffect(() =>
window.addEventListener(
'beforeunload',
saveStateToLocalStorage
);

return () =>
window.removeEventListener(
'beforeunload',
saveStateToLocalStorage
);

saveStateToLocalStorage();
;
, []);


const [ videoProgress, setVideoProgress ] = useState(0);

const saveStateToLocalStorage = () =>
const videosPlayedDuration =
[vimeoId]: videoProgress, // here I'm not getting updated videoProgress state, only default value
;

// here I will save videosPlayedDuration to the storage
;

return createPortal(
<div className="video-modal-background" onClick=onVideoClose>
<div className="video-modal-window">
<ReactPlayer
playing=true
url=VIMEO_URL + vimeoId
onProgress=videoProgress => setVideoProgress(videoProgress.playedSeconds) // here I'm setting state
/>
</div>
</div>,
document.getElementById('modal-root')
);
;

export default VideoItem;


So the as you can see I'm trying to use updated state but all I'm getting there is 0 as a default state.










share|improve this question



















  • 2





    That's because your useEffect hook is only run once after the initial render, so the saveStateToLocalStorage reference inside of the function given to it will always be a reference to the saveStateToLocalStorage of the initial render.

    – Tholle
    Mar 25 at 10:40













3












3








3








I cannot see the updated state inside of the helper method I'm using. All those worked in the class-based component, but it seems to be not the same when using hooks. Check out my comments.



import React, useEffect, useRef, useState from 'react';
import createPortal from 'react-dom';
import ReactPlayer from 'react-player';

import VIMEO_URL from '../../consts/urls';
import storage from '../../utils/localStorage';

const STORAGE_VIDEOS_DATA_KEY = 'VIDEOS_DATA';

import './VideoItem.scss';


const VideoItem = ( vimeoId ) =>
useEffect(() =>
window.addEventListener(
'beforeunload',
saveStateToLocalStorage
);

return () =>
window.removeEventListener(
'beforeunload',
saveStateToLocalStorage
);

saveStateToLocalStorage();
;
, []);


const [ videoProgress, setVideoProgress ] = useState(0);

const saveStateToLocalStorage = () =>
const videosPlayedDuration =
[vimeoId]: videoProgress, // here I'm not getting updated videoProgress state, only default value
;

// here I will save videosPlayedDuration to the storage
;

return createPortal(
<div className="video-modal-background" onClick=onVideoClose>
<div className="video-modal-window">
<ReactPlayer
playing=true
url=VIMEO_URL + vimeoId
onProgress=videoProgress => setVideoProgress(videoProgress.playedSeconds) // here I'm setting state
/>
</div>
</div>,
document.getElementById('modal-root')
);
;

export default VideoItem;


So the as you can see I'm trying to use updated state but all I'm getting there is 0 as a default state.










share|improve this question
















I cannot see the updated state inside of the helper method I'm using. All those worked in the class-based component, but it seems to be not the same when using hooks. Check out my comments.



import React, useEffect, useRef, useState from 'react';
import createPortal from 'react-dom';
import ReactPlayer from 'react-player';

import VIMEO_URL from '../../consts/urls';
import storage from '../../utils/localStorage';

const STORAGE_VIDEOS_DATA_KEY = 'VIDEOS_DATA';

import './VideoItem.scss';


const VideoItem = ( vimeoId ) =>
useEffect(() =>
window.addEventListener(
'beforeunload',
saveStateToLocalStorage
);

return () =>
window.removeEventListener(
'beforeunload',
saveStateToLocalStorage
);

saveStateToLocalStorage();
;
, []);


const [ videoProgress, setVideoProgress ] = useState(0);

const saveStateToLocalStorage = () =>
const videosPlayedDuration =
[vimeoId]: videoProgress, // here I'm not getting updated videoProgress state, only default value
;

// here I will save videosPlayedDuration to the storage
;

return createPortal(
<div className="video-modal-background" onClick=onVideoClose>
<div className="video-modal-window">
<ReactPlayer
playing=true
url=VIMEO_URL + vimeoId
onProgress=videoProgress => setVideoProgress(videoProgress.playedSeconds) // here I'm setting state
/>
</div>
</div>,
document.getElementById('modal-root')
);
;

export default VideoItem;


So the as you can see I'm trying to use updated state but all I'm getting there is 0 as a default state.







reactjs react-hooks






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 25 at 12:14









Ali

9801 gold badge13 silver badges30 bronze badges




9801 gold badge13 silver badges30 bronze badges










asked Mar 25 at 10:37









MurakamiMurakami

5745 silver badges17 bronze badges




5745 silver badges17 bronze badges







  • 2





    That's because your useEffect hook is only run once after the initial render, so the saveStateToLocalStorage reference inside of the function given to it will always be a reference to the saveStateToLocalStorage of the initial render.

    – Tholle
    Mar 25 at 10:40












  • 2





    That's because your useEffect hook is only run once after the initial render, so the saveStateToLocalStorage reference inside of the function given to it will always be a reference to the saveStateToLocalStorage of the initial render.

    – Tholle
    Mar 25 at 10:40







2




2





That's because your useEffect hook is only run once after the initial render, so the saveStateToLocalStorage reference inside of the function given to it will always be a reference to the saveStateToLocalStorage of the initial render.

– Tholle
Mar 25 at 10:40





That's because your useEffect hook is only run once after the initial render, so the saveStateToLocalStorage reference inside of the function given to it will always be a reference to the saveStateToLocalStorage of the initial render.

– Tholle
Mar 25 at 10:40












2 Answers
2






active

oldest

votes


















1














If you want to have componentWillUnmount behavior use useRef to access the updated values inside your listener:



 const [ videoProgress, setVideoProgress ] = useState(0);
const videoProgressRef = useRef(videoProgress);
useEffect(() => videoProgressRef.current = videoProgress, [videoProgress]);

function saveStateToLocalStorage()
const videosPlayedDuration =
[vimeoId]: videoProgressRef.current,
;


useEffect(() =>
window.addEventListener(
'beforeunload',
saveStateToLocalStorage
);

return () =>
window.removeEventListener(
'beforeunload',
saveStateToLocalStorage
);

saveStateToLocalStorage();
;
, []);


If you use saveStateToLocalStorage only inside useEffect it is better to move it inside the callback of useEffect. So it doesn't get recreated every render:



 useEffect(() => 
function saveStateToLocalStorage()
const videosPlayedDuration =
[vimeoId]: videoProgressRef.current,
;


window.addEventListener(
'beforeunload',
saveStateToLocalStorage
);

return () =>
window.removeEventListener(
'beforeunload',
saveStateToLocalStorage
);

saveStateToLocalStorage();
;
, []);





share|improve this answer
































    1














    The problem is caused due to closure. Since the effect is run only on initial render, the listener holds reference of saveStateToLocalStorage which gets the state value from its closure only on initial render and hence the updated value isn't visible inside it.



    You need to remove and add listener whenever the videoProgress state changes. In order to do that you can pass videoProgress as the second argument to useEffect



    const VideoItem = ( vimeoId ) => 
    const [ videoProgress, setVideoProgress ] = useState(0);
    useEffect(() =>
    window.addEventListener(
    'beforeunload',
    saveStateToLocalStorage
    );

    return () =>
    window.removeEventListener(
    'beforeunload',
    saveStateToLocalStorage
    );

    saveStateToLocalStorage();
    ;
    , [videoProgress]);


    function saveStateToLocalStorage()
    const videosPlayedDuration =
    [vimeoId]: videoProgress,
    ;

    ;

    return createPortal(
    <div className="video-modal-background" onClick=onVideoClose>
    <div className="video-modal-window">
    <ReactPlayer
    playing=true
    url=VIMEO_URL + vimeoId
    onProgress=videoProgress => setVideoProgress(videoProgress.playedSeconds) // here I'm setting state
    />
    </div>
    </div>,
    document.getElementById('modal-root')
    );
    ;

    export default VideoItem;





    share|improve this answer

























    • There will be a ReferenceError: saveStateToLocalStorage is not defined, as you use it before its definition.

      – ᆼᆺᆼ
      Mar 25 at 10:49












    • That is because function expressions are not hoisted. If you declare it as a function declaration, it will work

      – Shubham Khatri
      Mar 25 at 10:50












    • I guess you meant to write that const declarations are not hoisted.

      – ᆼᆺᆼ
      Mar 25 at 10:52







    • 1





      yes, I updated the code too

      – Shubham Khatri
      Mar 25 at 10:54











    • Thanks for answering. I guess we are rendering a component too many times though. I only would like to fire useEffect on componentDidMount and componentWillUnmount. Now it saves to the storage every 1 second but I need to do that only when component mounts and unmounts.

      – Murakami
      Mar 25 at 10:54













    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55335898%2fcant-see-state-inside-method-helper-function-using-hooks%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    If you want to have componentWillUnmount behavior use useRef to access the updated values inside your listener:



     const [ videoProgress, setVideoProgress ] = useState(0);
    const videoProgressRef = useRef(videoProgress);
    useEffect(() => videoProgressRef.current = videoProgress, [videoProgress]);

    function saveStateToLocalStorage()
    const videosPlayedDuration =
    [vimeoId]: videoProgressRef.current,
    ;


    useEffect(() =>
    window.addEventListener(
    'beforeunload',
    saveStateToLocalStorage
    );

    return () =>
    window.removeEventListener(
    'beforeunload',
    saveStateToLocalStorage
    );

    saveStateToLocalStorage();
    ;
    , []);


    If you use saveStateToLocalStorage only inside useEffect it is better to move it inside the callback of useEffect. So it doesn't get recreated every render:



     useEffect(() => 
    function saveStateToLocalStorage()
    const videosPlayedDuration =
    [vimeoId]: videoProgressRef.current,
    ;


    window.addEventListener(
    'beforeunload',
    saveStateToLocalStorage
    );

    return () =>
    window.removeEventListener(
    'beforeunload',
    saveStateToLocalStorage
    );

    saveStateToLocalStorage();
    ;
    , []);





    share|improve this answer





























      1














      If you want to have componentWillUnmount behavior use useRef to access the updated values inside your listener:



       const [ videoProgress, setVideoProgress ] = useState(0);
      const videoProgressRef = useRef(videoProgress);
      useEffect(() => videoProgressRef.current = videoProgress, [videoProgress]);

      function saveStateToLocalStorage()
      const videosPlayedDuration =
      [vimeoId]: videoProgressRef.current,
      ;


      useEffect(() =>
      window.addEventListener(
      'beforeunload',
      saveStateToLocalStorage
      );

      return () =>
      window.removeEventListener(
      'beforeunload',
      saveStateToLocalStorage
      );

      saveStateToLocalStorage();
      ;
      , []);


      If you use saveStateToLocalStorage only inside useEffect it is better to move it inside the callback of useEffect. So it doesn't get recreated every render:



       useEffect(() => 
      function saveStateToLocalStorage()
      const videosPlayedDuration =
      [vimeoId]: videoProgressRef.current,
      ;


      window.addEventListener(
      'beforeunload',
      saveStateToLocalStorage
      );

      return () =>
      window.removeEventListener(
      'beforeunload',
      saveStateToLocalStorage
      );

      saveStateToLocalStorage();
      ;
      , []);





      share|improve this answer



























        1












        1








        1







        If you want to have componentWillUnmount behavior use useRef to access the updated values inside your listener:



         const [ videoProgress, setVideoProgress ] = useState(0);
        const videoProgressRef = useRef(videoProgress);
        useEffect(() => videoProgressRef.current = videoProgress, [videoProgress]);

        function saveStateToLocalStorage()
        const videosPlayedDuration =
        [vimeoId]: videoProgressRef.current,
        ;


        useEffect(() =>
        window.addEventListener(
        'beforeunload',
        saveStateToLocalStorage
        );

        return () =>
        window.removeEventListener(
        'beforeunload',
        saveStateToLocalStorage
        );

        saveStateToLocalStorage();
        ;
        , []);


        If you use saveStateToLocalStorage only inside useEffect it is better to move it inside the callback of useEffect. So it doesn't get recreated every render:



         useEffect(() => 
        function saveStateToLocalStorage()
        const videosPlayedDuration =
        [vimeoId]: videoProgressRef.current,
        ;


        window.addEventListener(
        'beforeunload',
        saveStateToLocalStorage
        );

        return () =>
        window.removeEventListener(
        'beforeunload',
        saveStateToLocalStorage
        );

        saveStateToLocalStorage();
        ;
        , []);





        share|improve this answer















        If you want to have componentWillUnmount behavior use useRef to access the updated values inside your listener:



         const [ videoProgress, setVideoProgress ] = useState(0);
        const videoProgressRef = useRef(videoProgress);
        useEffect(() => videoProgressRef.current = videoProgress, [videoProgress]);

        function saveStateToLocalStorage()
        const videosPlayedDuration =
        [vimeoId]: videoProgressRef.current,
        ;


        useEffect(() =>
        window.addEventListener(
        'beforeunload',
        saveStateToLocalStorage
        );

        return () =>
        window.removeEventListener(
        'beforeunload',
        saveStateToLocalStorage
        );

        saveStateToLocalStorage();
        ;
        , []);


        If you use saveStateToLocalStorage only inside useEffect it is better to move it inside the callback of useEffect. So it doesn't get recreated every render:



         useEffect(() => 
        function saveStateToLocalStorage()
        const videosPlayedDuration =
        [vimeoId]: videoProgressRef.current,
        ;


        window.addEventListener(
        'beforeunload',
        saveStateToLocalStorage
        );

        return () =>
        window.removeEventListener(
        'beforeunload',
        saveStateToLocalStorage
        );

        saveStateToLocalStorage();
        ;
        , []);






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Mar 25 at 12:19

























        answered Mar 25 at 12:12









        UjinT34UjinT34

        2,2701 gold badge3 silver badges16 bronze badges




        2,2701 gold badge3 silver badges16 bronze badges























            1














            The problem is caused due to closure. Since the effect is run only on initial render, the listener holds reference of saveStateToLocalStorage which gets the state value from its closure only on initial render and hence the updated value isn't visible inside it.



            You need to remove and add listener whenever the videoProgress state changes. In order to do that you can pass videoProgress as the second argument to useEffect



            const VideoItem = ( vimeoId ) => 
            const [ videoProgress, setVideoProgress ] = useState(0);
            useEffect(() =>
            window.addEventListener(
            'beforeunload',
            saveStateToLocalStorage
            );

            return () =>
            window.removeEventListener(
            'beforeunload',
            saveStateToLocalStorage
            );

            saveStateToLocalStorage();
            ;
            , [videoProgress]);


            function saveStateToLocalStorage()
            const videosPlayedDuration =
            [vimeoId]: videoProgress,
            ;

            ;

            return createPortal(
            <div className="video-modal-background" onClick=onVideoClose>
            <div className="video-modal-window">
            <ReactPlayer
            playing=true
            url=VIMEO_URL + vimeoId
            onProgress=videoProgress => setVideoProgress(videoProgress.playedSeconds) // here I'm setting state
            />
            </div>
            </div>,
            document.getElementById('modal-root')
            );
            ;

            export default VideoItem;





            share|improve this answer

























            • There will be a ReferenceError: saveStateToLocalStorage is not defined, as you use it before its definition.

              – ᆼᆺᆼ
              Mar 25 at 10:49












            • That is because function expressions are not hoisted. If you declare it as a function declaration, it will work

              – Shubham Khatri
              Mar 25 at 10:50












            • I guess you meant to write that const declarations are not hoisted.

              – ᆼᆺᆼ
              Mar 25 at 10:52







            • 1





              yes, I updated the code too

              – Shubham Khatri
              Mar 25 at 10:54











            • Thanks for answering. I guess we are rendering a component too many times though. I only would like to fire useEffect on componentDidMount and componentWillUnmount. Now it saves to the storage every 1 second but I need to do that only when component mounts and unmounts.

              – Murakami
              Mar 25 at 10:54















            1














            The problem is caused due to closure. Since the effect is run only on initial render, the listener holds reference of saveStateToLocalStorage which gets the state value from its closure only on initial render and hence the updated value isn't visible inside it.



            You need to remove and add listener whenever the videoProgress state changes. In order to do that you can pass videoProgress as the second argument to useEffect



            const VideoItem = ( vimeoId ) => 
            const [ videoProgress, setVideoProgress ] = useState(0);
            useEffect(() =>
            window.addEventListener(
            'beforeunload',
            saveStateToLocalStorage
            );

            return () =>
            window.removeEventListener(
            'beforeunload',
            saveStateToLocalStorage
            );

            saveStateToLocalStorage();
            ;
            , [videoProgress]);


            function saveStateToLocalStorage()
            const videosPlayedDuration =
            [vimeoId]: videoProgress,
            ;

            ;

            return createPortal(
            <div className="video-modal-background" onClick=onVideoClose>
            <div className="video-modal-window">
            <ReactPlayer
            playing=true
            url=VIMEO_URL + vimeoId
            onProgress=videoProgress => setVideoProgress(videoProgress.playedSeconds) // here I'm setting state
            />
            </div>
            </div>,
            document.getElementById('modal-root')
            );
            ;

            export default VideoItem;





            share|improve this answer

























            • There will be a ReferenceError: saveStateToLocalStorage is not defined, as you use it before its definition.

              – ᆼᆺᆼ
              Mar 25 at 10:49












            • That is because function expressions are not hoisted. If you declare it as a function declaration, it will work

              – Shubham Khatri
              Mar 25 at 10:50












            • I guess you meant to write that const declarations are not hoisted.

              – ᆼᆺᆼ
              Mar 25 at 10:52







            • 1





              yes, I updated the code too

              – Shubham Khatri
              Mar 25 at 10:54











            • Thanks for answering. I guess we are rendering a component too many times though. I only would like to fire useEffect on componentDidMount and componentWillUnmount. Now it saves to the storage every 1 second but I need to do that only when component mounts and unmounts.

              – Murakami
              Mar 25 at 10:54













            1












            1








            1







            The problem is caused due to closure. Since the effect is run only on initial render, the listener holds reference of saveStateToLocalStorage which gets the state value from its closure only on initial render and hence the updated value isn't visible inside it.



            You need to remove and add listener whenever the videoProgress state changes. In order to do that you can pass videoProgress as the second argument to useEffect



            const VideoItem = ( vimeoId ) => 
            const [ videoProgress, setVideoProgress ] = useState(0);
            useEffect(() =>
            window.addEventListener(
            'beforeunload',
            saveStateToLocalStorage
            );

            return () =>
            window.removeEventListener(
            'beforeunload',
            saveStateToLocalStorage
            );

            saveStateToLocalStorage();
            ;
            , [videoProgress]);


            function saveStateToLocalStorage()
            const videosPlayedDuration =
            [vimeoId]: videoProgress,
            ;

            ;

            return createPortal(
            <div className="video-modal-background" onClick=onVideoClose>
            <div className="video-modal-window">
            <ReactPlayer
            playing=true
            url=VIMEO_URL + vimeoId
            onProgress=videoProgress => setVideoProgress(videoProgress.playedSeconds) // here I'm setting state
            />
            </div>
            </div>,
            document.getElementById('modal-root')
            );
            ;

            export default VideoItem;





            share|improve this answer















            The problem is caused due to closure. Since the effect is run only on initial render, the listener holds reference of saveStateToLocalStorage which gets the state value from its closure only on initial render and hence the updated value isn't visible inside it.



            You need to remove and add listener whenever the videoProgress state changes. In order to do that you can pass videoProgress as the second argument to useEffect



            const VideoItem = ( vimeoId ) => 
            const [ videoProgress, setVideoProgress ] = useState(0);
            useEffect(() =>
            window.addEventListener(
            'beforeunload',
            saveStateToLocalStorage
            );

            return () =>
            window.removeEventListener(
            'beforeunload',
            saveStateToLocalStorage
            );

            saveStateToLocalStorage();
            ;
            , [videoProgress]);


            function saveStateToLocalStorage()
            const videosPlayedDuration =
            [vimeoId]: videoProgress,
            ;

            ;

            return createPortal(
            <div className="video-modal-background" onClick=onVideoClose>
            <div className="video-modal-window">
            <ReactPlayer
            playing=true
            url=VIMEO_URL + vimeoId
            onProgress=videoProgress => setVideoProgress(videoProgress.playedSeconds) // here I'm setting state
            />
            </div>
            </div>,
            document.getElementById('modal-root')
            );
            ;

            export default VideoItem;






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Mar 25 at 10:49

























            answered Mar 25 at 10:40









            Shubham KhatriShubham Khatri

            107k19 gold badges139 silver badges182 bronze badges




            107k19 gold badges139 silver badges182 bronze badges












            • There will be a ReferenceError: saveStateToLocalStorage is not defined, as you use it before its definition.

              – ᆼᆺᆼ
              Mar 25 at 10:49












            • That is because function expressions are not hoisted. If you declare it as a function declaration, it will work

              – Shubham Khatri
              Mar 25 at 10:50












            • I guess you meant to write that const declarations are not hoisted.

              – ᆼᆺᆼ
              Mar 25 at 10:52







            • 1





              yes, I updated the code too

              – Shubham Khatri
              Mar 25 at 10:54











            • Thanks for answering. I guess we are rendering a component too many times though. I only would like to fire useEffect on componentDidMount and componentWillUnmount. Now it saves to the storage every 1 second but I need to do that only when component mounts and unmounts.

              – Murakami
              Mar 25 at 10:54

















            • There will be a ReferenceError: saveStateToLocalStorage is not defined, as you use it before its definition.

              – ᆼᆺᆼ
              Mar 25 at 10:49












            • That is because function expressions are not hoisted. If you declare it as a function declaration, it will work

              – Shubham Khatri
              Mar 25 at 10:50












            • I guess you meant to write that const declarations are not hoisted.

              – ᆼᆺᆼ
              Mar 25 at 10:52







            • 1





              yes, I updated the code too

              – Shubham Khatri
              Mar 25 at 10:54











            • Thanks for answering. I guess we are rendering a component too many times though. I only would like to fire useEffect on componentDidMount and componentWillUnmount. Now it saves to the storage every 1 second but I need to do that only when component mounts and unmounts.

              – Murakami
              Mar 25 at 10:54
















            There will be a ReferenceError: saveStateToLocalStorage is not defined, as you use it before its definition.

            – ᆼᆺᆼ
            Mar 25 at 10:49






            There will be a ReferenceError: saveStateToLocalStorage is not defined, as you use it before its definition.

            – ᆼᆺᆼ
            Mar 25 at 10:49














            That is because function expressions are not hoisted. If you declare it as a function declaration, it will work

            – Shubham Khatri
            Mar 25 at 10:50






            That is because function expressions are not hoisted. If you declare it as a function declaration, it will work

            – Shubham Khatri
            Mar 25 at 10:50














            I guess you meant to write that const declarations are not hoisted.

            – ᆼᆺᆼ
            Mar 25 at 10:52






            I guess you meant to write that const declarations are not hoisted.

            – ᆼᆺᆼ
            Mar 25 at 10:52





            1




            1





            yes, I updated the code too

            – Shubham Khatri
            Mar 25 at 10:54





            yes, I updated the code too

            – Shubham Khatri
            Mar 25 at 10:54













            Thanks for answering. I guess we are rendering a component too many times though. I only would like to fire useEffect on componentDidMount and componentWillUnmount. Now it saves to the storage every 1 second but I need to do that only when component mounts and unmounts.

            – Murakami
            Mar 25 at 10:54





            Thanks for answering. I guess we are rendering a component too many times though. I only would like to fire useEffect on componentDidMount and componentWillUnmount. Now it saves to the storage every 1 second but I need to do that only when component mounts and unmounts.

            – Murakami
            Mar 25 at 10:54

















            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55335898%2fcant-see-state-inside-method-helper-function-using-hooks%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

            Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

            Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript