React 18 - 사용 효과가 두 번 호출되지 않도록 방지

6242 단어 react
작성자 크레딧: Niall Crosby



React 18은 엄격한 모드에서 모든 구성 요소가 마운트 및 마운트 해제된 다음 다시 마운트될 때 큰 변경 사항을 도입했습니다. 그 이유는 아직 React에 없는 기능을 위한 길을 닦기 위한 것이므로 React 18에 관한 한 그럴 이유가 없습니다.

React 18의 React Hooks의 경우 이는 종속성이 없는 useEffect()가 두 번 실행됨을 의미합니다.

다음은 종속성이 없는 useEffect() 대신 사용할 수 있는 사용자 정의 후크입니다. 이는 이전(React 18 이전) 동작을 다시 제공합니다. 즉, 브레이킹 체인지 주위에서 작동합니다.

다음은 TypeScript가 없는 사용자 지정 후크 useEffectOnce입니다.

export const useEffectOnce = ( effect )=> {

  const destroyFunc = useRef();
  const effectCalled = useRef(false);
  const renderAfterCalled = useRef(false);
  const [val, setVal] = useState(0);

  if (effectCalled.current) {
      renderAfterCalled.current = true;
  }

  useEffect( ()=> {

      // only execute the effect first time around
      if (!effectCalled.current) { 
        destroyFunc.current = effect();
        effectCalled.current = true;
      }

      // this forces one render after the effect is run
      setVal(val => val + 1);

      return ()=> {
        // if the comp didn't render since the useEffect was called,
        // we know it's the dummy React cycle
        if (!renderAfterCalled.current) { return; }
        if (destroyFunc.current) { destroyFunc.current(); }
      };
  }, []);
};


TypeScript를 사용한 후크는 다음과 같습니다.

export const useEffectOnce = (effect: () => void | (() => void)) => {
  const destroyFunc = useRef<void | (() => void)>();
  const effectCalled = useRef(false);
  const renderAfterCalled = useRef(false);
  const [val, setVal] = useState<number>(0);

  if (effectCalled.current) {
    renderAfterCalled.current = true;
  }

  useEffect(() => {
    // only execute the effect first time around
    if (!effectCalled.current) {
      destroyFunc.current = effect();
      effectCalled.current = true;
    }

    // this forces one render after the effect is run
    setVal((val) => val + 1);

    return () => {
      // if the comp didn't render since the useEffect was called,
      // we know it's the dummy React cycle
      if (!renderAfterCalled.current) {
        return;
      }
      if (destroyFunc.current) {
        destroyFunc.current();
      }
    };
  }, []);
};


애플리케이션 코드에서 useEffect 대신 의존성이 0인 useEffectOnce를 호출합니다. 작업 완료.

// instead of this:
useEffect( ()=> {
    console.log('my effect is running');
    return () => console.log('my effect is destroying');
}, []);

// do this:
useEffectOnce( ()=> {
    console.log('my effect is running');
    return () => console.log('my effect is destroying');
});


간단히 말해서 작동 방식은 React 18에서 관찰했습니다. 효과가 실행되고 렌더링되기 전에 다시 파괴되면 가짜 설정/파괴 주기임을 알 수 있습니다. 이는 React 버전과 엄격 모드 사용 여부에 관계없이 작동합니다.

매우 인기 있는 라이브러리인 AG Grid에서 이 해결 방법을 사용하므로 이 수정 사항은 "전투 테스트"를 거쳤습니다.

또한 이 글을 읽는 모든 AG Grid 사용자에게 분명히 말씀드리자면 이는 애플리케이션에서 수행해야 하는 작업이 아니며 내부적으로 구현한 해결 방법입니다. 이 때문에 AG Grid로 다른 작업을 수행할 필요가 없습니다.

좋은 웹페이지 즐겨찾기