programing

리액트 후크 useEffect는 업데이트 시에만 적용됩니까?

magicmemo 2023. 3. 27. 21:10
반응형

리액트 후크 useEffect는 업데이트 시에만 적용됩니까?

제한하고 싶은 경우useEffect컴포넌트가 마운트되었을 때만 실행되도록 하려면 , 다음의 파라메타를 추가할 수 있습니다.useEffect와 함께[].

useEffect(() => {
  // ...
}, []);

하지만 어떻게 하면useEffect초기 마운트를 제외한 컴포넌트가 업데이트되는 순간에만 실행할 수 있습니까?

useEffect를 초기 마운트를 제외한 업데이트에서만 실행하려면useRefinitialMount를 추적하다useEffect두 번째 매개 변수를 사용하지 않습니다.

const isInitialMount = useRef(true);

useEffect(() => {
  if (isInitialMount.current) {
     isInitialMount.current = false;
  } else {
      // Your useEffect code here to be run on update
  }
});

Shubham의 반응이 너무 좋아서 커스텀 훅으로 만들었어요.

/**
 * A custom useEffect hook that only triggers on updates, not on initial mount
 * @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 {
      return effect();
    }
  }, dependencies);
}

Shubham과 Mario 둘 다 올바른 접근법을 제안하지만, 코드는 아직 불완전하고 다음 사례를 고려하지 않습니다.

  1. 컴포넌트가 마운트 해제되면 해당 플래그를 리셋해야 합니다.
  2. 지나감effect함수는 호출되지 않는 정리 함수를 반환할 수 있습니다.

위의 두 가지 누락 사례를 다루는 보다 완전한 코드 아래에 공유:

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
};

쇼트 원

const [mounted, setMounted] = useRef(false)

useEffect(() => {
  if(!mounted) return setMounted(true)
  ...
})

리액트 훅 솔루션

후크

export const useMounted = () => {
  const mounted = useRef(false)

  useEffect(() => {
    mounted.current = true
    return () => {
      mounted.current = false
    }
  }, [])

  return () => mounted.current
}

사용.

const Component = () => {
  const mounted = useMounted()

  useEffect(() => {
    if(!mounted()) return
    ...
  })
}

상태를 비부울 초기값(null 값 등)으로 설정하면 회피할 수 있습니다.

  const [isCartOpen,setCartOpen] = useState(null);
  const [checkout,setCheckout] = useState({});

  useEffect(() => {

    // check to see if its the initial state
    if( isCartOpen === null ){

      // first load, set cart to real initial state, after load
      setCartOpen( false );
    }else if(isCartOpen === false){

      // normal on update callback logic
      setCartOpen( true );
    }
  }, [checkout]);

Subham의 답변에 도움을 받았습니다.이 코드는 특정 아이템의 업데이트에만 실행되며, 모든 업데이트에서는 실행되지 않으며, 컴포넌트의 초기 마운트에서는 실행되지 않습니다.

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])

실제로 의존 관계를 전달할 필요가 없는 훅 규칙에 따라 커스텀 훅을 만들려면 효과 함수를 useCallback으로 랩합니다.

function useEffectOnUpdate(callback) {
  const mounted = useRef();

  useEffect(() => {
    if (!mounted.current) {
      mounted.current = true;
    } else {
      callback();
    }
  }, [callback]);
};

function SomeComponent({ someProp }) {
  useEffectOnUpdate(useCallback(() => {
    console.log(someProp);
  }, [someProp]));

  return <div>sample text</div>;
}

청소 기능을 사용합니다.useEffect빈 배열을 두 번째 매개 변수로 사용하지 않습니다.

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

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

언급URL : https://stackoverflow.com/questions/55075604/react-hooks-useeffect-only-on-update

반응형