source

react hooks useEffect() 청소는 componentWillUnmount만 해당합니까?

gigabyte 2023. 3. 20. 23:16
반응형

react hooks useEffect() 청소는 componentWillUnmount만 해당합니까?

이 코드의 결과를 알기 쉽게 설명해 드리겠습니다.

const ForExample = () => {
    const [name, setName] = useState('');
    const [username, setUsername] = useState('');

    useEffect(() => {
        console.log('effect');
        console.log({
            name,
            username
        });

        return () => {
            console.log('cleaned up');
            console.log({
                name,
                username
            });
        };
    }, [username]);

    const handleName = e => {
        const { value } = e.target;

        setName(value);
    };

    const handleUsername = e => {
        const { value } = e.target;

        setUsername(value);
    };

    return (
        <div>
            <div>
                <input value={name} onChange={handleName} />
                <input value={username} onChange={handleUsername} />
            </div>
            <div>
                <div>
                    <span>{name}</span>
                </div>
                <div>
                    <span>{username}</span>
                </div>
            </div>
        </div>
    );
};

?ForExample component마운트, '효과'가 기록됩니다.은 '아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아.componentDidMount().

그리고 이름 입력을 변경할 때마다 '효과'와 '정리'가 모두 기록됩니다.사용자 .는 사용자 이름 입력을 했기 때문입니다.[username]인 '''에 대해서''useEffect()는 ' 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 이런componentDidUpdate()

이 , 이 경우, 이.ForExample component언마운트하면 '백업'이 기록됩니다.은 '아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아.componentWillUnmount().

그건 우리 모두 알고 있어

즉, 컴포넌트가 재렌더될 때마다(마운트 해제 포함) '정리'가 호출됩니다.

에만 ' cleaning 두 번째 파라미터인 '를.useEffect()로로 합니다.[].

만약 가 변한다면[username]로로 합니다.[],ForExample component 이행을 .componentDidUpdate()이름을 입력합니다.

것은 가 양쪽을 지원하도록입니다.componentDidUpdate() 및 " " "만 해당됩니다.componentWillUnmount() (만 '.) (컴포넌트를 마운트 해제하는 순간만 '충돌')

여러 useEffect()를 사용할 수 있습니다.

들어 가 " " "인 "data1컴포넌트에서 이 모든 것을 사용할 수 있습니다.

useEffect( () => console.log("mount"), [] );
useEffect( () => console.log("data1 update"), [ data1 ] );
useEffect( () => console.log("any update") );
useEffect( () => () => console.log("data1 update or unmount"), [ data1 ] );
useEffect( () => () => console.log("unmount"), [] );

는 「」에하지 않기 에, 「」에 의존하지 않습니다.username 할 수 useEffect빈 배열이 두 번째 인수로 지정됩니다.

const { useState, useEffect } = React;

const ForExample = () => {
  const [name, setName] = useState("");
  const [username, setUsername] = useState("");

  useEffect(
    () => {
      console.log("effect");
    },
    [username]
  );

  useEffect(() => {
    return () => {
      console.log("cleaned up");
    };
  }, []);

  const handleName = e => {
    const { value } = e.target;

    setName(value);
  };

  const handleUsername = e => {
    const { value } = e.target;

    setUsername(value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={handleName} />
        <input value={username} onChange={handleUsername} />
      </div>
      <div>
        <div>
          <span>{name}</span>
        </div>
        <div>
          <span>{username}</span>
        </div>
      </div>
    </div>
  );
};

function App() {
  const [shouldRender, setShouldRender] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setShouldRender(false);
    }, 5000);
  }, []);

  return shouldRender ? <ForExample /> : null;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

수용된 답변에 덧붙이자면, 저는 유사한 문제를 가지고 있으며, 아래의 계획적인 예시와 같은 방법으로 해결했습니다. 몇 가지 .componentWillUnmount원래 질문에서 설명한 것처럼 매개 변수가 변경될 때마다 기록되지 않았으면 합니다.

const componentWillUnmount = useRef(false)

// This is componentWillUnmount
useEffect(() => {
    return () => {
        componentWillUnmount.current = true
    }
}, [])

useEffect(() => {
    return () => {
        // This line only evaluates to true after the componentWillUnmount happens 
        if (componentWillUnmount.current) {
            console.log(params)
        }
    }

}, [params]) // This dependency guarantees that when the componentWillUnmount fires it will log the latest params

사용자 지정 js 이벤트를 사용하면 종속성이 있는 경우에도 componentWillUnmount를 에뮬레이트할 수 있습니다.

문제:

    useEffect(() => {
    //Dependent Code
    return () => {
        // Desired to perform action on unmount only 'componentWillUnmount' 
        // But it does not
        if(somethingChanged){
            // Perform an Action only if something changed
        }
    }
},[somethingChanged]);

솔루션:

// Rewrite this code  to arrange emulate this behaviour

// Decoupling using events
useEffect( () => {
    return () => {
        // Executed only when component unmounts,
        let e = new Event("componentUnmount");
        document.dispatchEvent(e);
    }
}, []);

useEffect( () => {
    function doOnUnmount(){
        if(somethingChanged){
            // Perform an Action only if something changed
        }
    }

    document.addEventListener("componentUnmount",doOnUnmount);
    return () => {
        // This is done whenever value of somethingChanged changes
        document.removeEventListener("componentUnmount",doOnUnmount);
    }

}, [somethingChanged])

주의: useEffect는 순서대로 작성해야 합니다.의존관계가 없는 useEffect는 삭제 후 이벤트가 호출되지 않도록 하기 위해 작성해야 합니다.

다음과 같이 간단하게 쓸 수 있습니다.

  useEffect(() => {
  return () => {};
  }, []);
function LegoComponent() {

  const [lego, setLegos] = React.useState([])

  React.useEffect(() => {
    let isSubscribed = true
    fetchLegos().then( legos=> {
      if (isSubscribed) {
        setLegos(legos)
      }
    })
    return () => isSubscribed = false
  }, []);

  return (
    <ul>
    {legos.map(lego=> <li>{lego}</li>)}
    </ul>
  )
}

위의 코드에서는 fetchLegos 함수가 약속을 반환합니다.useEffect 범위에 조건을 붙여서 컴포넌트가 마운트 해제된 후 앱 상태가 설정되는 것을 방지함으로써 약속을 "취소"할 수 있습니다.

경고:마운트 해제된 구성 요소에서 반응 상태 업데이트를 수행할 수 없습니다.이것은 no-op이지만, 애플리케이션의 메모리 누수를 나타내고 있습니다.수정하려면 useEffect 정리 함수의 모든 구독 및 비동기 작업을 취소합니다.

복잡한 함수나 메서드를 너무 많이 만드는 대신 이벤트 리스너를 생성하여 수동으로 할 필요 없이 자동으로 마운트 및 마운트 해제를 수행합니다.여기 예가 있습니다.

//componentDidMount
useEffect( () => {

    window.addEventListener("load",  pageLoad);

    //component will unmount
    return () => {
       
        window.removeEventListener("load", pageLoad);
    }

 });

이제 이 파트가 완성되었으니 pageLoad 함수에서 원하는 대로 실행할 수 있습니다.

const pageLoad = () =>{
console.log(I was mounted and unmounted automatically :D)}

커스텀 훅으로 일반화된 솔루션을 다음에 나타냅니다.

import React, { useEffect, useRef } from 'react';

const useUnmountEffect = (effect, dependencies) => {
  if (typeof effect !== 'function') {
    console.error('Effect must be a function');
  }

  const componentWillUnmount = useRef(false)

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

  useEffect(() => () => {
    if (componentWillUnmount.current) {
      effect?.();
    }
  }, dependencies);
}

export default useUnmountEffect;

useEffect는 자체 범위 내에서 분리되고 그에 따라 렌더링됩니다.이미지: https://reactjs.org/docs/hooks-custom.html

여기에 이미지 설명 입력

에 대해서:

function useOnUnmount(callback: () => void) {
    const onUnmount = useRef<(() => void) | null>(null);
    onUnmount.current = callback;

    useEffect(() => {
        return () => onUnmount.current?.();
    }, []);
}

useOnUnmount(() => {
    console.log("unmount", props);
});

언급URL : https://stackoverflow.com/questions/55020041/react-hooks-useeffect-cleanup-for-only-componentwillunmount

반응형