Developer/React

React , useEffect / 컴포넌트의 시작 ,업데이트, 끝을 관리하자(생애 주기 관리)

단님 2024. 6. 13. 20:29
728x90
컴포넌트의 생애주기 (LifeCycle)

 

UI를 구성하기 위해서는 화면에 컴포넌트를

시작(최초의 랜더링) ,  - Mounting

값이 바뀌면 업데이트(리랜더링) , - Updating  

삭제(또는 변경(즉 삭제후 새로운 시작))로 - Unmounting(unmounting 이후 새로운 Mounting)

이루어 져있다.

함수형 컴포넌트는 이의 생애주기마다 실행할 수 있는 훅이 존재한다.

 

바로 그 훅이 useEffect.

최초 랜더링에만 이런 함수를 실행해줘 ,

=> Mounting : 컴포넌트를 페이지에 처음 랜더링 할때 

 

이 값만 바뀌었을때 이런 함수를 실행해줘,

 => Updating : State, Props 값이 바뀌거나 부모컴포넌트가 리랜더 하면서 자신도 리랜더 될때

 

이 컴포넌트가 없어질때 이런 함수를 실행해줘 같은 내가 원하는 시점에 대한 함수실행 컨트롤이 가능해진다.

=> Unmounting : 컴포넌트가 페이지에서 제거될때 (더이상 랜더링하지않음)

 

즉 , 컴포넌트가 특정 시점일때의 특정 작업을 실행할 수 있도록 도와준다.

 

use Effect 사용 방법 

 

import { useState , useEffect} from 'react';

1. useEffect 를 react 에서 import

 

useEffect(callback_함수, [deps]_의존성 배열)

 

-첫번쨰 인자로의 콜백 함수로는 특정 조건일때의 실행할 함수를 쓰면 된다.

-두번째 인자의 배열은 의존성 배열이라고 하며 , useEffect 의 조건에 해당하는 부분이 된다.

 

조건은 어떻게 걸고 , 어떻게 사용하는건지 확인해보겠다.

 

app.js -> 값이 바뀔때마다 부모와 프롭스로 연결된 자식이 랜더링이 일어남

  const [count, setCount] = useState(0);
  const [text, setText] = useState('');
  const onChangeCount = (e) => {
    setCount(count + e);
  }
  const onChangeText = (e) => {
    setText(e.target.value);
  }
  
  
 console.log('app 랜더링');
  return (
    <div>
      <h1>Simlpe Counter & </h1>
      <h1>함수 컴포넌트의 LifeCycle</h1>
      <section>
        <Viewer count={count} />
        <Controller onChangeCount={onChangeCount} />
        {count % 2 === 1 || <Even count={count} />}
      </section>
      <section>
        <input value={text} onChange={onChangeText} />
      </section>
    </div>

 

 

1. 카운트 변수가 변했을때만(랜더링이 일어났을 때만) 콘솔을 찍어볼게.
useEffect(()=>{
    console.log(`useEffect test count ${count}`);
  },[count]); //count가 랜더링 된다면 , 콜백함수가 실행될것이다.

 

최초 마운트 시점에 실행된 후 

배열안의 count 가 값이 바뀔때마다

즉 , count 의 랜더링이 이루어질때마다 useEffect 가 실행되는것을 확인가능하다.

input의 text 변수가 변하면 부모는 랜더링이 되지만 , count 의 값이 바뀐것이 아님으로 

  useEffect(()=>{
    console.log(`useEffect test count ${count}`);
  },[count]);
 
이 실행문은 실행 되지 않음.

 

 

2. count 변수와 text 변수가 값이 바뀌면 실행할게
useEffect(()=>{
    console.log(`useEffect test count ${count}`);
    console.log(`useEffect test text ${text}`);
  },[count,text]); //count와 text 랜더링 된다면 , 콜백함수가 실행될것이다.

text 변수가 변할때도 감지하여 useEffect 의 콜백함수가 실행되는것을 드디어 볼 수 있다.

 

이것으로 볼 수 있듯
즉, useEffect는 배열안의 상태값이 바뀐다면,
콜백함수가 실행된다는 것을 알 수 있다.
그로인해 특정 컴포넌트가 업데이트가 되었을때의 시점이 제어가 가능하다.

 

이쯤 이제 궁금해지기 시작한다.

배열로 컨트롤하니 ,

빈배열이되면  ? 아니 그냥 빈배열도 없으면 ?

 

그렇다. 그 나머지 생애주기를 컨트롤 하는 방법중 하나들이다.

 

3. 빈 배열을 이용해볼게
  useEffect(()=>{
    console.log(`useEffect test count ${count}`);
    console.log(`useEffect test text ${text}`);
  },[])

첫 로드에만 실행이 되고 , 나머지는 실행되지 않는 것이 확인 가능하다.

즉 , 첫로드 → 컴포넌트의 마운트 시점에 실행이 가능하다는 것이 확인 가능하다.

 

4. 빈배열 조차 없다면 어떻게 될까 ?

 

  useEffect(()=>{
    console.log(`useEffect test count ${count}`);
    console.log(`useEffect test text ${text}`);
  },);

배열 자체가 없다면 , 모든 랜더링을 감지하게 된다.

그렇다면 굳이 useEffect를 쓸 이유가 없게 된다.

그냥 컴포넌트 안에 변수를 사용하면 똑같이 작동할텐데.

 

하지만 이 또한 필요 할 때가 있다.

현재까지의 모든 방법엔 첫마운트의 실행이 포함 되어있다. 

만약 첫 마운트의 실행을 제외하고 어느 특정 랜더링 또는 모든 랜더링을 감지하고 싶다면 ?

 

ref를 사용하여 첫 실행을 막을 수 있다.

import { useState , useEffect , useRef} from 'react';
const didMountRef = useRef(false);
  useEffect(()=>{
    if(!didMountRef.current){
      didMountRef.current = true;
    }else{
      console.log(`useEffect test count : ${count}`);
      console.log(`useEffect test text : ${text}`);
    }
  });

  console.log('app 랜더링');

Ref 를 통해 쓰는이유는 단순하다.

일반 변수를 쓴다면 계속 랜더링이 될때마다 false의 값이 리셋되어 실행 조차 될수 없다.

랜더링에도 값을 저장하여 보관해야 하기 때문에 Ref 를 활용하여 조절할 수 있다.

값 입력후

 

 

unmounting 은 어떻게 제어할까 ?

 

unmounting 의 실행은 useEffect를 이용하여 , 특정 값이 변경되기 직전에 실행할 작업을 지정한다.

 

실행 방법은 이렇다.

useEffect(() => {
        console.log('컴포넌트가 화면에 나타남');
        return () => {
            console.log('컴포넌트가 화면에서 사라짐')
        }
    }, [])

 

클린업 함수라고 불리는데

return 뒤에 콜백함수를 지정하는 방법이다.

컴포넌트가 사라질 때(unmount 시점), 특정 값이 변경되기 직전(deps update 직전)에 실행할 작업을 지정할 수 있다.

 

 

const Even = ({count})=>{
    // => 클린업 함수
    //    - useEffect 의 콜백함수에서 return 하는 함수
    //    - 콜백함수를 재호출하기 전에 실행됨.
    useEffect(()=>{
        return ()=>{
            console.log('Even 컴포넌트의 언마운트')
        };
    }); //재호출 하기 직전에 나오는 함수.
  return (
    <div>
      <h1>Simlpe Counter & </h1>
      <h1>함수 컴포넌트의 LifeCycle</h1>
      <section>
        <Viewer count={count} />
        <Controller onChangeCount={onChangeCount} />
        {count%2 ===0 && <Even count={count}/>}
      </section>
      <section>
        <input value={text} onChange={onChangeText} />
      </section>
    </div>
  );
}

특정 조건(count가 짝수일때)을 만족해야 Even 이 실행된다.

짝수에서 홀수가 되는 시점에서 컴포넌트가 사라질때 return이 실행되는것이 확인 가능하다.

 

 

useEffect에서의 setInterval의 사용

 

useEffect 에서 상태값을 바꾸거나 setInterval을 이용하게되면 ,

무한 루프에 빠지기 쉽다.

랜더링이 일어날때의 최초시점으로 계속 반복이 되거나.

값이 계속 증가하면서 계속 useEffect가 실행 되면서 내가 원하지 않는 상황이 발생한다.

그렇기에 최초의 랜더링이 될 때 이전의 실행을 클리어 하여 지워주면 된다.

  useEffect(()=>{
    let time = setInterval(() => {
      console.log('useEffcet 속의 setInterval');
    }, 1000);
    return ()=>{
      console.log('clearinterval');
      clearInterval(time)
    }
  })