React useEffect 생애주기(생명주기)

YongWan·2023년 3월 10일
0

React Basic

목록 보기
6/10
post-thumbnail

React 컴포넌트의 생애 주기 (생명 주기)

탄생(화면에 나타나는 것 Mount) -> 변화(업데이트(리렌더) Update) -> 죽음(화면에서 사라짐 UnMount)

React는 기본적으로 Lifecycle마다 실행할 수 있는 메서드를 가지고 있다.

  • ComponentDidMount (Mount)
  • ComponentDidUpdate (Update)
  • ComponentWillUnmount (UnMount)

다만 위의 메서드들은 class형 컴포넌트에서만 사용할 수 있다.

useEffect

// 함수형 컴포넌트에서 Lifecycle를 제어하기 위해서는 useEffect라는 React Hooks를 사용해야 한다.
useEffect(() => {
  // todo... // Callback 함수
}, []) // [] => Dependency Array(의존성 배열) 이 배열 내에 들어있는 값이 변화하면 콜백 함수가 수행된다.
useEffect(() => {
    // Dependency Array가 있을 경우 최초 렌더 됐을때만 아래의 'Mount!'가 출력된다. 리렌더X
    console.log('Mount!');
  }, []);
  useEffect(() => {
    // Dependency Array를 전달하지 않을 경우 리렌더링 될 때마다 'Update!'가 출력된다.
    console.log('Update!');
  });
  const [count, setCount] = useState(0);
  useEffect(() => {
    // console.log(`count is update : ${count}`);
    if(count > 5) {
      alert('count가 5를 넘었습니다. 따라서 1로 초기화 됩니다.');
      setCount(1);
    }
  }, [count]); // Dependency Array의 값이 변경되면 콜백 함수가 수행된다.

Dependency Array([])가 비어 있을 경우 최초 렌더 되었을 경우만 실행
Dependency Array([])가 없다면 리렌더링 될때마다 실행
Dependency Array([value])에 값이 전달된다면 그 값이 변경될때 실행

useEffect 활용1

// 부모 컴포넌트
import { useState } from "react"
import Products from "./components/Products";

export default function AppProducts() {
  const [showProducts, setShowProducts] = useState(true);
  return (
    <div>
      // showProducts가 true일 경우만 Products컴포넌트를 보여준다.
      {showProducts && <Products/>}
      // Toogle 기능 구현
      <button onClick={() => setShowProducts((show) => !show)}>Toogle</button>
    </div>
  )
}

잘못된 예

아래와 같이 fetch를 하게 되면 setProducts가 Products 함수를 계속 호출하면서 무한 루프에 빠진다.

// 자식 컴포넌트
import { useEffect, useState } from "react"

export default function Products() {
  const [count, setCount] = useState(0);
  const [products, setProducts] = useState([]);

  // 무한 루프에 빠진다.
   fetch('data/products.json')
     .then(res => res.json())
     .then(data => {
     setProducts(data);
   });
  
  return (
    <>
      <ul>
        {products.map(elm => (
          <li key={elm.id}>
            <article>
              <h3>{elm.name}</h3>
              <h3>{elm.price}</h3>
            </article>
          </li>
        ))}
      </ul>
      <button onClick={() => setCount(prev => prev + 1)}>{count}</button>
    </>
  )
}

올바른 예

// 자식 컴포넌트
import { useEffect, useState } from "react"

export default function Products() {
  const [count, setCount] = useState(0);
  const [products, setProducts] = useState([]);

  useEffect(() => {
    fetch(`data/${checked ? 'sale_' : ''}products.json`)
      .then(res => res.json())
      .then(data => {
        setProducts(data);
      });
      return () => {
        console.log('🧹 깨끗하게 청소하는 일들을 합니다.')
      }
  // Dependency Array를 빈 배열로 넣어주게 되면 컴포넌트가 보여지는 최초에만 네트워크 요청을 한다.
  }, []);
  
  return (
    <>
      <ul>
        {products.map(elm => (
          <li key={elm.id}>
            <article>
              <h3>{elm.name}</h3>
              <h3>{elm.price}</h3>
            </article>
          </li>
        ))}
      </ul>
      <button onClick={() => setCount(prev => prev + 1)}>{count}</button>
    </>
  )
}

useEffect 활용1-1

만약 컴포넌트가 없어질때 무언가 정리(메모리 정리, 소켓 네트워크 통신 닫기...)해야 한다면
useEffect에 return 함수를 전달해주면 된다.

  useEffect(() => {
    fetch(`data/${checked ? 'sale_' : ''}products.json`)
      .then(res => res.json())
      .then(data => {
        setProducts(data);
      });
      // 이 콜백함수는 컴포넌트가 없어질때 즉 화면에서 사라질때(Unmount) 호출되는 함수다.
      return () => {
      	console.log('🧹 깨끗하게 청소하는 일들을 합니다.')
   	  }
  }, []);

useEffect 활용2

어떤 특정한 값이 변경될 때만 네트워크 요청을 하고 싶은 경우

import { useEffect, useState } from "react"

export default function Products() {
  const [count, setCount] = useState(0);
  const [products, setProducts] = useState([]);
  // checked 초기값 셋팅
  const [checked, setChecked] = useState(false);
  // 상태관리 함수
  const handleChange = () => setChecked(prev => !prev);

  useEffect(() => {
    // checked가 true일 경우 세일 정보 json 요청
    // checked가 false일 경우 일반 정보 json 요청
    fetch(`data/${checked ? 'sale_' : ''}products.json`)
      .then(res => res.json())
      .then(data => {
        setProducts(data);
      });
      // 컴포넌트가 화면에서 사라질때 실행되는 콜백함수
      return () => {
        console.log('🧹 깨끗하게 청소하는 일들을 합니다.')
      }
  // checked의 값이 변경될때마다 네트워크 요청을 하게 된다.
  }, [checked]);
  
  return (
    <>
      // value prop으로 전달하는 checked의 초기값은 false다.
      // onChange가 발생할때마다 handleChange를 참조해 참 or 거짓으로 변경한다.
      <input id="checkbox" type="checkbox" value={checked} onChange={handleChange} />
      <label htmlFor="checkbox">Show Only 🛎️ Sale</label>
      <ul>
        {products.map(elm => (
          <li key={elm.id}>
            <article>
              <h3>{elm.name}</h3>
              <h3>{elm.price}</h3>
            </article>
          </li>
        ))}
      </ul>
      <button onClick={() => setCount(prev => prev + 1)}>{count}</button>
    </>
  )
}

고유한 key값

// Error 발생!
return (
    <>
      <input id="checkbox" type="checkbox" value={checked} onChange={handleChange} />
      <label htmlFor="checkbox">Show Only 🛎️ Sale</label>
      <ul>
        // 아래와 같이 자식 요소들을 만들때 고유한 key값이 없으면 Error가 발생한다.
        // 아래의 경우는 json파일에 id key가 없어서 Error가 발생했다.
        {products.map(elm => (
          // key값 전달!!
          <li key={elm.id}>
            <article>
              <h3>{elm.name}</h3>
              <h3>{elm.price}</h3>
            </article>
          </li>
        ))}
      </ul>
      <button onClick={() => setCount(prev => prev + 1)}>{count}</button>
    </>
  )

0개의 댓글