programing

useEffect를 사용하면 첫 번째 렌더링에 효과 적용을 생략할 수 있습니까?

lovejava 2023. 3. 25. 09:11

useEffect를 사용하면 첫 번째 렌더링에 효과 적용을 생략할 수 있습니까?

React의 새로운 Effect Hooks를 사용하면 리렌더 간에 특정 값이 변경되지 않은 경우 이펙트를 적용하지 않도록 React에게 지시할 수 있습니다(React 문서의 예:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

에서는 첫 번째 및에 이 됩니다.count다다 how. 하면 할 수 요?리액트에게 초기 렌더링에 대한 영향을 건너뛰도록 지시하려면 어떻게 해야 합니까?

가이드의 설명대로

효과 후크(useEffect)는 함수 성분의 부작용을 수행하는 기능을 추가합니다.React 클래스의 componentDidMount, componentDidUpdate 및 componentWillUnmount와 동일한 목적을 수행하지만 단일 API로 통합됩니다.

는 안내서의 예시로, '대로 하다'라고 되어 있습니다.count0으로 하다. 0으로 하다

const [count, setCount] = useState(0);

이렇게 하면 '이렇게 하다'라고 할 수 요.componentDidUpdate"이것들"은 다음과 같습니다.

useEffect(() => {
  if (count)
    document.title = `You clicked ${count} times`;
}, [count]);

으로 사용 입니다.useEffect작작: :

function useDidUpdateEffect(fn, inputs) {
  const didMountRef = useRef(false);

  useEffect(() => {
    if (didMountRef.current) { 
      return fn();
    }
    didMountRef.current = true;
  }, inputs);
}

@Tholle을 은 @.useRefsetState.

현재 렌더가 첫 번째 렌더인지(컴포넌트가 마운트된 시점)를 나타내는 부울 플래그만 제공하는 사용자 지정 후크가 있습니다.할 수 .useEffect렌더링 기능이나 원하는 컴포넌트 내의 다른 장소에서도 사용할 수 있습니다.누군가 더 좋은 이름을 제안할 수 있을지도 몰라

import { useRef, useEffect } from 'react';

export const useIsMount = () => {
  const isMountRef = useRef(true);
  useEffect(() => {
    isMountRef.current = false;
  }, []);
  return isMountRef.current;
};

다음과 같이 사용할 수 있습니다.

import React, { useEffect } from 'react';

import { useIsMount } from './useIsMount';

const MyComponent = () => {
  const isMount = useIsMount();

  useEffect(() => {
    if (isMount) {
      console.log('First Render');
    } else {
      console.log('Subsequent Render');
    }
  });

  return isMount ? <p>First Render</p> : <p>Subsequent Render</p>;
};

관심이 있는 경우 다음 테스트를 실시합니다.

import { renderHook } from '@testing-library/react-hooks';

import { useIsMount } from '../useIsMount';

describe('useIsMount', () => {
  it('should be true on first render and false after', () => {
    const { result, rerender } = renderHook(() => useIsMount());
    expect(result.current).toEqual(true);
    rerender();
    expect(result.current).toEqual(false);
    rerender();
    expect(result.current).toEqual(false);
  });
});

사용 사례는 애니메이션 요소를 숨겨야 할 경우 애니메이션 요소를 숨기는 것이었습니다.나중에 렌더링할 때 소품이 변경되면 요소를 애니메이션으로 만들고 싶었습니다.

저는 더 간단하고 다른 훅을 사용할 필요가 없는 솔루션을 찾았지만, 단점이 있습니다.

useEffect(() => {
  // skip initial render
  return () => {
    // do something with dependency
  }
}, [dependency])

이것은 단순한 경우 다른 방법이 있다는 것을 보여주는 예에 불과합니다.

이렇게 하면 정리 효과가 없고 종속 배열이 두 번째로 변경될 때만 실행됩니다.

이 방법은 권장되지 않으며 다른 답변과 동일하게 사용해야 합니다. 그러나 이 방법은 여러 가지가 있다는 것을 알리기 위해 여기에 추가한 것입니다.

편집:

더 명확하게 하기 위해 질문의 문제를 해결하기 위해 이 방법을 사용하면 됩니다(초기 렌더링을 건너뛰는 것). 이는 동일한 작업을 다른 방식으로 수행할 수 있음을 보여주는 교육 목적으로만 사용됩니다.초기 렌더링을 건너뛰어야 할 경우 다른 답변에 접근하십시오.

참조 대신 정규 상태 변수를 사용합니다.

// Initializing didMount as false
const [didMount, setDidMount] = useState(false)

// Setting didMount to true upon mounting
useEffect(() => { setDidMount(true) }, [])

// Now that we have a variable that tells us wether or not the component has
// mounted we can change the behavior of the other effect based on that
const [count, setCount] = useState(0)
useEffect(() => {
  if (didMount) document.title = `You clicked ${count} times`
}, [count])

이와 같이 didMount 로직을 커스텀훅으로 리팩터링할 수 있습니다.

function useDidMount() {
  const [didMount, setDidMount] = useState(false)
  useEffect(() => { setDidMount(true) }, [])

  return didMount
}

마지막으로 이렇게 컴포넌트에 사용할 수 있습니다.

const didMount = useDidMount()

const [count, setCount] = useState(0)
useEffect(() => {
  if (didMount) document.title = `You clicked ${count} times`
}, [count])

UPDATE useRef 을 사용하여 추가 렌더를 회피합니다(@TomEsterez의 제안 덕분에).

이번에는 사용자 지정 후크가 참조의 현재 값을 반환하는 함수를 반환합니다.레퍼런스도 직접 사용할 수 있지만 저는 이게 더 좋아요.

function useDidMount() {
  const mountRef = useRef(false);

  useEffect(() => { mountRef.current = true }, []);

  return () => mountRef.current;
}

사용.

const MyComponent = () => {
  const didMount = useDidMount();

  useEffect(() => {
    if (didMount()) // do something
    else // do something else
  })

  return (
    <div>something</div>
  );
}

참고로 저는 이 후크를 사용할 필요가 없었습니다.리액트 프로그래밍 모델에 보다 적합한 더 나은 방법이 있을 것입니다.

리액션 용도를 소개합니다.

npm install react-use

실행:

첫 번째 렌더링 에만? ----------------->useUpdateEffect

1회만? ------------------------->useEffectOnce

첫 번째 마운트인지 확인합니다. ----------------->useFirstMountState

심층 비교, 얕은 비교 또는 스로틀로 효과를 실행하시겠습니까?많은 것들이 있습니다.

라이브러리를 설치하지 않으시겠습니까?코드와 복사를 확인합니다.(아마도star★★★★★★★★★★★★★★★★★★★★★★★★★★」

가장 좋은 것은 당신이 유지할 수 있는 것이 하나 적다는 것이다.

및을 TypeScript "CRA", "CRA"로 합니다.useEffect 이 는 '고리다'처럼요useEffect첫 번째 렌더가 실행되는 동안에는 트리거되지 않습니다.

import * as React from 'react'

export const useLazyEffect:typeof React.useEffect = (cb, dep) => {
  const initializeRef = React.useRef<boolean>(false)

  React.useEffect((...args) => {
    if (initializeRef.current) {
      cb(...args)
    } else {
      initializeRef.current = true
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, dep)
}

다음은 타이프스크립트에 기재된 Estus Flask의 답변을 바탕으로 한 구현입니다.또한 청소 콜백도 지원합니다.

import { DependencyList, EffectCallback, useEffect, useRef } from 'react';

export function useDidUpdateEffect(
  effect: EffectCallback,
  deps?: DependencyList
) {
  // a flag to check if the component did mount (first render's passed)
  // it's unrelated to the rendering process so we don't useState here
  const didMountRef = useRef(false);

  // effect callback runs when the dependency array changes, it also runs
  // after the component mounted for the first time.
  useEffect(() => {
    // if so, mark the component as mounted and skip the first effect call
    if (!didMountRef.current) {
      didMountRef.current = true;
    } else {
      // subsequent useEffect callback invocations will execute the effect as normal
      return effect();
    }
  }, deps);
}

라이브 데모

아래 라이브 데모에서는 다음 두 가지 차이점을 보여 줍니다.useEffect ★★★★★★★★★★★★★★★★★」useDidUpdateEffect

53179075 / use-effect-how-can-i-skip-apply-an-effect-the-initial-render 편집

현재 접수된 답변에 대해 코멘트를 드리려고 했는데 공간이 부족합니다!

첫째, 기능 컴포넌트를 사용할 때는 라이프 사이클 이벤트라는 관점에서 사고하는 것에서 벗어나는 것이 중요합니다.제안/상태 변화에 대해 생각해 보십시오.도 비슷한 , 한 을 원했어.useEffect가 있을 때 .parentValue내 경우)는 초기 상태에서 변경됩니다.그래서 초기값을 기반으로 한 참조를 작성했습니다.

const parentValueRef = useRef(parentValue);

, '다르다'의 첫머리에 과 같은 을 넣었습니다.useEffectfn:

if (parentValue === parentValueRef.current) return;
parentValueRef.current = parentValue;

이펙트)는 (이펙트)를 .parentValue변하지 않았어요.참조가 변경된 경우 업데이트하고 다음 검사를 준비한 후 계속 실행합니다.)

따라서 제시된 다른 솔루션이 귀하가 제공한 특정 사용 사례를 해결할 수 있지만, 장기적으로는 기능 구성요소에 대한 생각을 바꾸는 데 도움이 됩니다.

주로 일부 소품을 기반으로 구성 요소를 렌더링하는 것으로 생각해 보십시오.

만약 당신이 정말로 지방 자치체가 필요하다면,useState로컬 상태를 저장함으로써 문제가 해결된다고 가정하지 마십시오.

렌더링 중에 소품을 변경하는 코드가 있는 경우 이 '부작용'은 로 감싸야 합니다.useEffect단, 렌더링 중 변경되는 내용에 영향을 받지 않는 깨끗한 렌더링을 제공하는 것이 목적입니다.useEffect후크는 렌더가 완료된 후 실행되며, 지적하신 대로 모든 렌더와 함께 실행됩니다.단, 이후 실행되는 변경된 항목을 식별하는 데 두 번째 매개 변수가 소품/상태 목록을 제공하는 데 사용되지 않는 한 모든 렌더링과 함께 실행됩니다.

기능 컴포넌트 / 후크로의 이행에 행운을 빕니다.새로운 작업 방식을 이해하기 위해 무언가를 배울 필요가 있을 수 있습니다:) 이것은 훌륭한 입문서입니다.https://overreacted.io/a-complete-guide-to-useeffect/

아래 솔루션은 위와 비슷하며, 조금 더 깔끔한 방법을 선호합니다.

const [isMount, setIsMount] = useState(true);
useEffect(()=>{
        if(isMount){
            setIsMount(false);
            return;
        }
        
        //Do anything here for 2nd render onwards
}, [args])

마운트 후 사용자 지정 후크를 사용하여 사용 효과를 실행할 수 있습니다.

const useEffectAfterMount = (cb, dependencies) => {
  const mounted = useRef(true);

  useEffect(() => {
    if (!mounted.current) {
      return cb();
    }
    mounted.current = false;
  }, dependencies); // eslint-disable-line react-hooks/exhaustive-deps
};

.typescript★★★★

const useEffectAfterMount = (cb: EffectCallback, dependencies: DependencyList | undefined) => {
  const mounted = useRef(true);

  useEffect(() => {
    if (!mounted.current) {
      return cb();
    }
    mounted.current = false;
  }, dependencies); // eslint-disable-line react-hooks/exhaustive-deps
};

예:

useEffectAfterMount(() => {
  document.title = `You clicked ${count} times`;
}, [count])

언급URL : https://stackoverflow.com/questions/53179075/with-useeffect-how-can-i-skip-applying-an-effect-upon-the-initial-render