React hooks useEffect only on update?

前端 未结 8 947
予麋鹿
予麋鹿 2020-12-12 18:53

If we want to restrict useEffect to run only when the component mounts, we can add second parameter of useEffect with [].



        
相关标签:
8条回答
  • 2020-12-12 19:30

    Use the Cleanup function of the useEffect without using an empty array as a second parameter:

    useEffect(() => { 
      return () => {
      // your code to be run only on update
      }
    });
    

    If you wish, you can use another useEffect (with an empty array as a second parameter) for initial mount, where you place the code in its main function as usual.

    0 讨论(0)
  • 2020-12-12 19:31

    Took help from Subham's answer This code will only run for particular item update not on every update and not on component initial mounting.

    const isInitialMount = useRef(true);    //useEffect to run only on updates except initial mount
    
    
    //useEffect to run only on updates except initial mount
      useEffect(() => {
        if (isInitialMount.current) {
            isInitialMount.current = false;
         } else {              
             if(fromScreen!='ht1' && appStatus && timeStamp){
                // let timeSpentBG = moment().diff(timeStamp, "seconds");
                // let newHeatingTimer = ((bottomTab1Timer > timeSpentBG) ? (bottomTab1Timer - timeSpentBG) : 0);
                // dispatch({
                //     type: types.FT_BOTTOM_TAB_1,
                //     payload: newHeatingTimer,
                // })
                // console.log('Appstaatus', appStatus, timeSpentBG, newHeatingTimer)
             }
         }
      }, [appStatus])
    
    0 讨论(0)
  • 2020-12-12 19:33

    A shorter one

    const [mounted, setMounted] = useRef(false)
    
    useEffect(() => {
      if(!mounted) return setMounted(true)
      // your update codes goes here
    });
    
    
    0 讨论(0)
  • 2020-12-12 19:35

    I really like Shubham's response, so I made it a custom Hook

    /**
     * A custom useEffect hook that only triggers on updates, not on initial mount
     * Idea stolen from: https://stackoverflow.com/a/55075818/1526448
     * @param {Function} effect
     * @param {Array<any>} dependencies
     */
    export default function useUpdateEffect(effect, dependencies = []) {
      const isInitialMount = useRef(true);
    
      useEffect(() => {
        if (isInitialMount.current) {
          isInitialMount.current = false;
        } else {
          effect();
        }
      }, dependencies);
    }
    
    0 讨论(0)
  • 2020-12-12 19:39

    Another approach would be to call useEffect twice or more, depending on the 'concern'. Please see Rudy Nappée's answer from the comments down below the blog post:

    https://dev.to/savagepixie/how-to-mimic-componentdidupdate-with-react-hooks-3j8c

    In a nutshell:

    useEffect(concern1, [...]);
    useEffect(concern2, [...]);
    ...
    

    For each instance of useEffect, pass a different array argument you are trying to watch.

    0 讨论(0)
  • 2020-12-12 19:40

    Both Shubham and Mario suggest the right approach, however the code is still incomplete and does not consider following cases.

    1. If the component unmounts, it should reset it's flag
    2. The passing effect function may have a cleanup function returned from it, that would never get called

    Sharing below a more complete code which covers above two missing cases:

    import React from 'react';
    
    const useIsMounted = function useIsMounted() {
      const isMounted = React.useRef(false);
    
      React.useEffect(function setIsMounted() {
        isMounted.current = true;
    
        return function cleanupSetIsMounted() {
          isMounted.current = false;
        };
      }, []);
    
      return isMounted;
    };
    
    const useUpdateEffect = function useUpdateEffect(effect, dependencies) {
      const isMounted = useIsMounted();
      const isInitialMount = React.useRef(true);
    
      React.useEffect(() => {
        let effectCleanupFunc = function noop() {};
    
        if (isInitialMount.current) {
          isInitialMount.current = false;
        } else {
          effectCleanupFunc = effect() || effectCleanupFunc;
        }
        return () => {
          effectCleanupFunc();
          if (!isMounted.current) {
            isInitialMount.current = true;
          }
        };
      }, dependencies); // eslint-disable-line react-hooks/exhaustive-deps
    };
    
    0 讨论(0)
提交回复
热议问题