스나이퍼팩토리 사전직무교육 (Day5)

짜스의 하루 ·2024년 9월 27일

useEffect

useEffect 훅은 컴포넌트 생명 주기에 따른 코드를 작성하고 싶을 때 사용할 수 있는 훅입니다. 아래와 같은 기본 문법 형식을 가집니다.

useEffect(콜백, 의존성 배열); // dependencies array
useEffect(() => {}, []);

컴포넌트 생명주기

컴포넌트 생명주기란, 컴포넌트가 생성되고 삭제가 되는 순간까지 거쳐가는 일련의 주기를 말합니다. 리액트에서는 컴포넌트 생명주기를 ‘생성’, ‘수정(업데이트)’, ‘삭제’의 세 가지로 구분하고 있다.

컴포넌트 생성

컴포넌트가 생성되는 시점은 특정 컴포넌트가 웹 브라우저에 렌더링 되는 순간이다.

컴포넌트 삭제

컴포넌트가 삭제되는 시점은 특정 컴포넌트가 웹 브라우저에서 사라지는 순간이다.

컴포넌트 수정

컴포넌트가 수정되는 시점은 컴포넌트에서 관리하고 있는 상태 관리 변수의 값이 변경되었을 때 이다.


useEffect() 훅 사용하기

컴포넌트 생명주기의 각 시점은 useEffect() 훅으로 체크할 수 있다.

컴포넌트 생성 시점

import { useEffect } from "react";

export default function App() {
  useEffect(() => {
    console.log("Component Created");
  }, []);
  return <h1 className="text-3xl font-bold underline">Hello world!</h1>;
}

컴포넌트 수정 시점

import { useEffect, useState } from "react";

export default function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log("Component Count Updated!" + count);
  }, [count]);
  return (
    <>
      <h1>{count}</h1>
      <button onClick={() => setCount((count) => count + 1)}>클릭</button>
    </>
  );
}

간단하게 설명하자면,
useEffect 훅은 두 번째 인자로 전달된 배열의 값이 변경될 때만 실행된다.
--> 이 경우에는 [count] 배열이 전달되었으므로 count 상태가 변경될 때마다 useEffect 내부의 함수가 호출된다.

따라서 사용자가 버튼을 클릭하여 count를 증가시키면 setCount가 호출되고, 이로 인해 count가 변경되면서 useEffect가 실행되어 "Component Count Updated" 메시지가 콘솔에 출력되게 된다.

✚ useEffect 훅 내에서 정의한 정리(cleanup) 함수는 다음 두 가지 경우에 실행된다 :

  • 컴포넌트가 언마운트될 때: 컴포넌트가 DOM에서 제거될 때 정리 함수가 실행되어 리소스를 해제할 수 있다.
  • 의존성 배열의 값이 변경될 때: 의존성 배열에 있는 값이 변경되면 이전 useEffect의 정리 함수가 실행된 후, 새로운 useEffect가 실행된다.

따라서 return 문으로 정의한 함수는 컴포넌트가 종료될 때 또는 의존성이 변경되기 전에 실행되게 된다.

컴포넌트 삭제 시점

App.tsx

import { useState } from "react";
import Interval from "./components/Interval";

export default function App() {
  const [display, setDisplay] = useState(false);

  return (
    <>
      {display && <Interval />}
      <button onClick={() => setDisplay((display) => !display)}>클릭</button>
    </>
  );
}

useEffect, useLayoutEffect 의 차이

import React, { useEffect, useLayoutEffect, useState } from 'react';

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

  // useEffect(() => {
  //   if (count === 10) {
  //     setTimeout(() => {
  //       setCount(0);
  //     }, 2000);
  //   }
  // }, [count]);

  useLayoutEffect(() => {
    if (count === 10) {
      setTimeout(() => {
        setCount(0);
      }, 2000);
    }
  }, [count]);
  return (
    <>
      <div className="flex flex-col justify-start items-start">
        <h1>{count}</h1>
        <button onClick={() => setCount((prev) => prev + 1)}>버튼</button>
        <button onClick={() => setCount(10)}>10으로 이동 버튼</button>
      </div>
    </>
  );
}

useEffect

  • 실행 시점: 컴포넌트의 렌더링이 완료된 후, 브라우저가 화면을 업데이트 한 다음에 실행된다. 즉, DOM이 화면에 그려진 후에 사이드 이펙트를 실행한다.
  • 용도: 비동기 작업(예: 데이터 fetching, 타이머 설정)이나 DOM에 영향을 주지 않는 작업을 처리하는 데 적합하다.
  • 예시: API 호출, 이벤트 리스너 등록 등.

useLayoutEffect

  • 실행 시점: DOM 변경 후, 브라우저가 화면을 업데이트하기 전에 실행된다
    . 즉, DOM이 변경된 직후에 실행되어 화면이 업데이트되기 전에 사이드 이펙트를 실행한다.
  • 용도: DOM을 직접 수정하거나, 레이아웃 측정이 필요한 경우에 사용한다. 화면 깜빡임이나 레이아웃 변경이 발생하지 않도록 보장한다.
  • 예시: DOM 요소의 크기나 위치를 측정한 후 이를 기반으로 레이아웃을 조정하는 경우.

고차 컴포넌트란?

리액트에서 고차 컴포넌트(Higher-Order Component, HOC)는 컴포넌트를 인자로 받아서 새로운 컴포넌트를 반환하는 함수입니다. 고차 컴포넌트는 주로 컴포넌트의 재사용성과 코드의 모듈화를 높이기 위해 사용된다.

고차 컴포넌트의 개념

  1. 컴포넌트를 인자로 받는다: 고차 컴포넌트는 기존의 컴포넌트를 인자로 받아들인다.
  2. 새로운 컴포넌트를 반환한다: 인자로 받은 컴포넌트를 기반으로 새로운 컴포넌트를 생성하여 반환한다.

고차 컴포넌트의 용도

  • 코드 재사용: 여러 컴포넌트에서 공통적으로 필요한 로직이나 상태를 재사용할 수 있다.
  • 로직 분리: UI와 비즈니스 로직을 분리하여 더 깔끔한 코드를 작성할 수 있다.
  • 성능 최적화: 성능을 최적화하는 여러 기법을 적용할 수 있다.

React.memo

React.memo는 React에서 제공하는 고차 컴포넌트(Higher-Order Component)로, 함수형 컴포넌트를 메모이제이션(memoization)하여 성능을 최적화하는 데 사용된다.
기본적으로 React.memo는 주어진 컴포넌트가 동일한 props로 렌더링될 때, 이전에 렌더링된 결과를 재사용하게 함으로써 불필요한 렌더링을 방지하도록 되어져 있다.

import React, { useState } from 'react';

const Counter = React.memo(({ count }) => {
  console.log('Counter 렌더링');
  return <h1>{count}</h1>;
});

const App = () => {
  const [count, setCount] = useState(0);
  const [otherState, setOtherState] = useState(false);

  return (
    <div>
      <Counter count={count} />
      <button onClick={() => setCount(count + 1)}>Count Up</button>
      <button onClick={() => setOtherState(!otherState)}>Toggle Other State</button>
    </div>
  );
};

export default App;

Counter 컴포넌트는 count가 변경될 때만 렌더링된다. --> otherState가 변경되더라도 Counter는 렌더링되지 않는다.


useCallback

useCallback 훅은 함수형 컴포넌트에서 함수를 메모이제이션 하는 데 사용된다.
여기서 메모이제이션이란, 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장하여 사용함으로써 동일한 계산의 반복 수행을 제거하여 성능 향상을 도모하는 기술을 말한다.

const cachedFn = useCallback(fn, dependencies)

import React, { useState } from 'react';

const functionSet = new Set();
const App = () => {
  const [count, setCount] = useState(0);
  const [count2, setCount2] = useState(0);
  const decrement = () => {
    setCount(count - 1);
  };
  const increment = () => {
    setCount(count + 1);
  };
  const otherIncrement = () => {
    setCount2(count2 + 1);
  };

  functionSet.add(decrement);
  functionSet.add(increment);
  functionSet.add(otherIncrement);

  console.log(functionSet);
  return (
    <div>
      <h1>Count:{count}</h1>
      <button onClick={decrement}>-</button>
      <button onClick={increment}>+</button>
      <hr />
      <h1>Count2:{count2}</h1>
      <button onClick={otherIncrement}>+</button>
    </div>
  );
};

export default App;

메모이제이션: decrement, increment, otherIncrement 함수에 useCallback을 적용하여 이 함수들이 의존성 배열이 변경되지 않는 한 동일한 참조를 유지하도록 하였다.

성능 최적화: useCallback을 사용함으로써 컴포넌트가 리렌더링될 때마다 이 함수들이 새로 생성되지 않으므로, functionSet의 내용이 변하지 않고 메모리 사용이 최적화 된다.


useMemo

useMemo 훅은 값을 메모이제이션 하는 훅이다.
여기서 메모이제이션이란, 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장하여 사용함으로써 동일한 계산의 반복 수행을 제거하여 성능 향상을 도모하는 기술을 말한다.

import React, { useState, useMemo } from 'react';

const App = () => {
  const [count, setCount] = useState(0);
  const [otherCount, setOtherCount] = useState(0);

  // count의 제곱을 계산하는 함수
  const squaredCount = useMemo(() => {
    console.log('Count의 제곱을 계산 중...');
    return count * count;
  }, [count]); // count가 변경될 때만 재계산

  return (
    <div>
      <h1>Count: {count}</h1>
      <h2>Count의 제곱: {squaredCount}</h2>
      <button onClick={() => setCount(count + 1)}>Count 증가</button>
      <hr />
      <h1>Other Count: {otherCount}</h1>
      <button onClick={() => setOtherCount(otherCount + 1)}>Other Count 증가</button>
    </div>
  );
};

export default App;

squaredCount는 useMemo를 사용하여 count의 제곱 값을 메모이제이션 한다.
의존성 배열에 count를 넣어, count가 변경될 때만 계산이 이루어지도록 한다.

이때, count가 변경되지 않는 한 이전의 계산 결과를 재사용하므로 성능이 향상된다.

렌더링:
버튼 클릭 시 count를 증가시키면, squaredCount의 값이 새롭게 계산된다.
otherCount 버튼을 클릭해도 squaredCount는 재계산되지 않는다.


리액트 컨턱스트

useReducer

조금 더 복잡한 상태 관리를 할 때 사용하는 리액트 훅이다. 넓은 범위에서 useState 훅과 비슷하다.

const [state, dispatch] = useReducer(reducer, initialState)

import { useReducer } from "react";
import "./Counter.css";

const reducer = (state: number, action: { type: string }) => {
  switch (action.type) {
    case "increament":
      return state + 1;
    case "decreament":
      return state - 1;
    default:
      return state;
  }
};

const Counter = () => {
  const [counter, dispatch] = useReducer(reducer, 0);
  return (
    <div className="counter">
      <h1>{counter}</h1>
      <div>
        <button onClick={() => dispatch({ type: "decreament" })}>-</button>
        <button onClick={() => dispatch({ type: "increament" })}>+</button>
      </div>
    </div>
  );
};

export default Counter;

useContext

리액트의 useContext는 리액트 훅 중 하나로, 컨텍스트(Context)를 쉽게 사용하게 해주는 훅입니다. useContext를 사용하면 컨텍스트 API를 통해 전역적으로 상태를 관리하거나, 컴포넌트 트리에서 prop drilling을 피할 수 있습니다.

Context는 주로 애플리케이션에서 전역적으로 사용할 수 있는 데이터를 제공하는 데 사용된다.
예: 사용자 인증 상태, 테마 설정, 언어 선택 등.
Context는 React.createContext()를 사용하여 생성하고, Provider를 통해 데이터를 제공하며, useContext 훅을 통해 데이터를 소비할 수 있다.

import React, { createContext, useContext, useState } from 'react';

// 1. Context 생성
const ThemeContext = createContext();

const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

위에서 정의한 것을 useContext 훅을 사용해서 ThemeContext를 소비할 수 있다.

const ThemeSwitcher = () => {
  // 3. useContext로 컨텍스트 값 사용
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <div>
      <p>현재 테마: {theme}</p>
      <button onClick={toggleTheme}>테마 변경</button>
    </div>
  );
};

마지막을 ThemeProvider로 컴포넌트 트리를 감싸서 모든 하위 컴포넌트가 ThemeContext에 접근이 가능하도록 한다

const App = () => {
  return (
    <ThemeProvider>
      <ThemeSwitcher />
    </ThemeProvider>
  );
};

export default App;

본 후기는 본 후기는 [유데미x스나이퍼팩토리] 프로젝트 캠프 : Next.js 3기 과정(B-log) 리뷰로 작성 되었습니다.
#유데미 #udemy #웅진씽크빅 #스나이퍼팩토리 #인사이드아웃 #미래내일일경험 #프로젝트캠프 #부트캠프 #React #리액트프로젝트 #프론트엔드개발자양성과정 #개발자교육과정

profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글