React useEffect 뽀개기

수딩·2022년 6월 16일
0
post-thumbnail

useEffect

useEffect는 Hooks 에서 가장 중요한 개념이다 !

기본적으로 생김새는 아래 코드와 같이 생겼고, 콜백함수를 받는다.
콜백함수 내부에는 내가 원하는 코드를 작성해주면 됨 !

useEffect 코드는 두가지 작성법이 있는데,
첫번째는 렌더링이 될 때마다 실행되고

useEffect(()=>{
//작업 ..
});

두번째는 배열 (dependency array)을 받는데, 화면에 첫 렌더링이 될 때 + 배열 안의 value 값이 바뀔 때 실행되는 형식이다.

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

빈 배열을 전달받는다면, 그냥 화면에 첫 렌더링이 될 때만 실행된다.

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

이벤트를 만들었는데, 더이상 그 이벤트가 필요가 없다면 제거해주는 정리 작업(cleanup) 을 해줘야하는데 그럴 때 useEffect return으로 처리를 해주면 됨 !
(뒤에 타이머 예제로 더 알아보겠슴)

이렇게 함수를 return 해주면 해당 컴포넌트가 unmount 될 때, 혹은 다음 렌더링때 불릴 useEffect 가 실행되기 전에 return 내 함수가 실행이 된다!

count 업데이트 하기

update 버튼을 누를때마다 count 가 update 되게 만들어보자.

useEffect 를 사용하기 위해서는 우선 useState처럼 import 해와야 한다.

import { useState, useEffect } from "react";

function App() {
  const [count, setCount] = useState(1);

  const handleCountUpdate = () => {
    setCount(count + 1);
  };
  // 렌더링 될 때마다 매번 실행됨
  useEffect(() => {
    console.log("렌더링");
    //컴포넌트가 화면에 렌더링 된 직후에 콘솔에 찍히는 것
  });

  return (
    <div>
      <button onClick={handleCountUpdate}>Update</button>
      <span>count : {count}</span>
    </div>
  );
}

먼저 const [count, setCount] = useState(1); 로 count를 업데이트 할 state를 만들어주고, button 을 클릭할 때마다 handleCountUpdate 함수가 동작하게 작성해주었다.
그리고 useEffect 를 작성해 주었는데 컴포넌트가 화면에 렌더링 된 직후에 콘솔에 "렌더링" 이 찍히게 해보았다.

  useEffect(() => {
    console.log("렌더링");
  });

자 이번에는 아래 이미지처럼 input 값을 입력했을 때 바로 출력되게끔 한 번 만들어 보겠음

위 코드에서 이 코드들을 추가해서 만들어 줬음 .

const [name, setName] = useState("");

const handleInputChange = (e) => {
    setName(e.target.value);
  };
   <input type="text" value={name} onChange={handleInputChange} />
    <span>name : {name}</span>

이제 input창에 값을 입력할 때 마다 useEffect 안의 있는 콜백이 계속 불리는데,
렌더링 될 때마다 콘솔에 찍어보며 확인헤보자

렌더링 옆에 붙어있는 숫자가 콜백이 계속 불려오는 숫자인데,
이렇게 매번 값을 업데이트 할 때마다 useEffect가 불려오는것? 넘 비효율적이다.
무거운게 불려오면 성능에도 좋지 못함.
그냥 name 업데이트는 무시하고 count 업데이트 때만 useEffect 를 실행시키고 싶다면?

바로

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

뒤에 배열을 받는 방법이다.

  useEffect(() => {
    console.log("렌더링");
    //컴포넌트가 화면에 렌더링 된 직후에 콘솔에 찍히는 것
  },[count]);

지금 작성하고 있는 코드에서는 count 만 받고 싶으니깐, [count]를 배열로 받아옴!
이제 이걸 실행하면은 첫 렌더링 때와 , update 버튼을 눌렀을 때만 count가 업데이트 될 때만 렌더링 되는 것 !!!

각각의 변화마다 useEffect 를 다르게 줘보면


  // 렌더링마다 매번 실행됨 - 렌더링 이후
  useEffect(() => {
    console.log("렌더링!");
  });
  // 마운트 + count 변화할 때마다 실행
  useEffect(() => {
    console.log("count 변화");
  }, [count]);

  // 마운트 + name 변화할 때마다 실행
  useEffect(() => {
    console.log("name 변화");
  }, [name]);

이렇게 각각의 요소 값이 업데이트 될때 useEffect 가 실행이 됨을 볼 수 있음

근데 저 렌더링을 처음 실행할 때만 보여주고 싶다면?????
=> 빈 배열값을 넣어주면 됩니다.

useEffect(() => {
    console.log("마운팅");
  }, []);

여기까지 최종 코드

import { useState, useEffect } from "react";

function App() {
  const [count, setCount] = useState(1);
  const [name, setName] = useState("");

  const handleCountUpdate = () => {
    setCount(count + 1);
  };

  const handleInputChange = (e) => {
    setName(e.target.value);
  };

 // 렌더링마다 매번 실행됨 - 렌더링 이후
  useEffect(() => {
    console.log("렌더링!");
  });
  
  // 마운트 + count 변화할 때마다 실행
  useEffect(() => {
    console.log("count 변화");
  }, [count]);

  // 마운트 + name 변화할 때마다 실행
  useEffect(() => {
    console.log("name 변화");
  }, [name]);

  //처음 마운팅될때만 실행
  useEffect(() => {
    console.log("마운팅");
  }, []);

  return (
    <div>
      <button onClick={handleCountUpdate}>Update</button>
      <span>count : {count}</span>
      <input type="text" value={name} onChange={handleInputChange} />
      <span>name : {name}</span>
    </div>
  );
}

export default App;

타이머와 clean up

clean up 에 대해 알아보자.
우선 src 파일 안에 components 파일을 만들고, Timer.jsx 를 만들어 준다.

import React, { useEffect } from "react";

const Timer = (props) => {
  useEffect(() => {
    const timer = setInterval(() => {
      console.log("타이머 돌아가는중");
    }, 1000);
  }, []);

  return (
    <div>
      <span>타이머를 시작합니다. 콘솔창을 봐주십셔</span>
    </div>
  );
};

export default Timer;

그리고 App.js 에 위에서 만들어준 Timer 을 import 해주고 코드작성 시작!

import { useState, useEffect } from "react";
import Timer from "./components/Timer"; 

function App() {
  const [showTimer, setShowTimer] = useState(false);

  return (
    <div>
      {/* showTimer 이 true 일때만 Timer 보여주기 */}
      {showTimer && <Timer />}
      <button onClick={() => setShowTimer(!showTimer)}>Toggle Timer</button>
    </div>
  );
}

export default App;

지금 여기 코드 보면 useState 가 false 이다.

  const [showTimer, setShowTimer] = useState(false);

아까 위에서 Input 넣을때는 값이었는데 이번에는 boolean 으로 준 것 .
여기서 원하는건
showTimer이 true 면 false 혹은 그 반대로 바뀌게 toggle .

<button onClick={() => setShowTimer(!showTimer)}>Toggle Timer</button>

setShowTimer(!showTimer) 이걸통해 showTimer이 true 면 false 혹은 그 반대로 바뀌게 해줌

근데 여기서 문제.
Toggle Timer 버튼을 꺼도 타이머가 계속 돌아감!

타이머가 끝났을 때 타이머를 종료해주기 위해서는
Timer.jsx 에서 Timer 함수에 clearInterval()함수를 추가해줘야 한다.
clearInterval 이 타이머를 정리하는, 그러니깐 끝내주는 아이라고 보면 된다!

import React, { useEffect } from "react";

const Timer = (props) => {
  useEffect(() => {
    const timer = setInterval(() => {
      console.log("타이머 돌아가는중");
    }, 1000);

    return () => {
      clearInterval(timer);
      console.log("타이머가 종료되었습니다.");
    };
  }, []);

  return (
    <div>
      <span>타이머를 시작합니다. 콘솔창을 봐주십셔</span>
    </div>
  );
};

export default Timer;

타이머와 같은 함수를 쓸때는 setInterval() & clearInterval() 세트라고 생각하기 !

profile
Front-End Developer ✨

0개의 댓글