프론트/React

[React] 중급: 그래서 어떻게 코딩해? with. Hook

초코chip 2024. 10. 30. 17:53

들어가며..

“어떤 결과를 보여줘야 하는지”에만 집중하고 “어떻게 작업을 수행할지”는 리액트가 알아서 함
IoC (Inversion of Control): 렌더링 관리 책임을 리액트에 위임

 

  • 우리는 화면에 어떤 “결과(상태)“가 보여져야 하는지에만 집중
  • 즉, 원하는 결과(상태)만 정의하고, 변화가 필요할 때는 그 결과(상태)만 업데이트
  • React는 일반적인 JS와는 다르게 직접적인 DOM 조작을 최소화하고, 상태 변화에 따라 자동으로 UI를 렌더링하는 패턴을 사용

 

코딩 순서

React에서는 상태와 컴포넌트를 기반으로 UI를 동적으로 업데이트하는 방식으로 진행

  1. 상태(state) 선언 및 초기화: useState을 이용해 컴포넌트 내부에서 동적으로 변하는 값을 상태로 선언하고 초기화
  2. 이벤트 핸들러 함수 정의: 특정 동작(클릭, 입력 등)에 따라 상태를 변경하는 함수를 정의
    • 해당 함수 내부에서 상태 변경 함수(setState 등)를 통해 UI 변경을 트리거
  3. 이벤트 핸들러 연결: onClick, onChange 등 JSX 속성을 사용해 이벤트 핸들러를 요소에 연결
  4. 상태 변화에 따른 UI 업데이트: 상태가 변경되면 해당 상태를 참조하는 컴포넌트는 자동으로 리렌더링 진행
import React, { useState } from 'react';

export default function Counter() {
  // 1. 상태 선언 및 초기화: count라는 상태를 0으로 초기화
  const [count, setCount] = useState(0);

  // 2. 이벤트 핸들러 함수 정의: count를 증가시키는 함수
  const handleIncrement = () => {
    setCount(count + 1); // 상태 변경
  };

  return (
    <div>
      <h1>Counter: {count}</h1> {/* 4. 상태 변화에 따른 UI 업데이트 */}
      
      {/* 3. 이벤트 핸들러 연결: onClick 속성을 통해 버튼 클릭 이벤트에 핸들러 연결 */}
      <button onClick={handleIncrement}>Increase</button>
    </div>
  );
}

 

Hook

  • 정의: 함수형 컴포넌트에서 상태(State)와 기타 React 기능을 추가할 수 있게 해주는 특별한 함수
  • 목적: 원래  클래스형 컴포넌트에서만 가능했던 기능들을, 함수형 컴포넌트에서도 가능하도록 도와주는 역할

 

렌더링 관련 Hook

UseEffect

  • 정의: 컴포넌트의 생명주기동안( 생성, 업데이트, 소멸..) 특정 작업을 수행할 수 있도록 해주는 함수
  • 목적: 상태 변화(렌더링) 이후 실행되어야 하는 부수적인 작업을 관리할때 사용
  • 구조:  useEffect(() => {}, [dependency]);  -> dependency에 따라 컴포넌트 시점을 지정가능
  • 종류
    • 처음 렌더링 될때 -  dependency에 빈 배열 전달 : useEffect(() => {}, []);
    • 값이 업데이트 될때 - dependency에 state 전달: useEffect(() => {}, [count]);
    • 컴포넌트가 사라질 때 실행 - 함수 안에서 클로저 함수 전달: useEffect(() => {return () => {} , []}
생성 및 소멸 시점 설정 업데이트 시점 설정

 

 

UseRef

      • 정의: DOM 요소 값의 변화(컴포넌트 내부 변화)를 추적할 때 사용
      • 특징: useRef로 저장된 값은 변경되어도 컴포넌트를 다시 렌더링하지 않음
      • 목작: 렌더링을 트리거하지 않고도 값이나 DOM 요소에 접근하고 싶을 때
        • 주로 Form 요소의 값 변경을 추적하지만, 변경될 때마다 컴포넌트를 다시 렌더링할 필요가 없을 때 사용
        • 최신 값을 특정 이벤트에서만 사용하고 싶을 때: 버튼을 눌렀을 때처럼 일정한 조건에서만 최신 값을 사용하고자 할 때

 

 

Dom 요소 추적 컴포넌트 내부 변화 추적

 

 

렌더링 성능 최적화 관련(메모이제이션) Hook

컴포넌트가 다시 렌더링될 때 계산 비용이 큰 작업을 반복해서 수행하지 않도록, 값을 메모이제이션(캐시처럼 저장)하여 불필요한 재계산을 방지

 

useMemo  - 값 메모이제이션 

  • 정의: 연산 비용이 큰 작업(예: 복잡한 계산)을 피하기 위해 값을 캐싱
  • 특징: useMemo는 설정한 의존성이 변경될 때만 계산을 실행
  • 구조: useMemo( () => 함수이름(limit), [limit] );
    • 첫번째 인자: 비싼 비용이 드는 함수
    • 두번째 인자: 의존성 배열, 배열 안에 있는 값들이 바뀔 때, 함수가 다시 실행 
이렇게 복잡한 연산을 하는 함수가 존재한다면 useMemo로 값을 메모이제이션 진행

 

 

useCallback - 함수 메모이제이션

    • 정의: 함수가 매번 새로 생성되는 것을 방지하여, 기존 함수를 재사용할 수 있도록 진행
    • 특징: useCallback은 설정한 의존성이 변경될 때만 함수 재정의
    • 구조: useCallback(함수, [의존성 배열])
      • 첫 번째 인자: 메모이제이션할 함수(콜백 함수)
      • 두 번째 인자: 의존성 배열, 이 배열의 값들이 변경될 때에만 함수가 재생성

 

전역 Props관련 Hook

useContext

    • 정의: 컴포넌트 트리 전체에 걸쳐 전역 상태를 공유하기 위한 Hook
    • 목적
      • 여러 컴포넌트에서 공유해야 할 데이터가 있는 경우
      • 컴포넌트 트리의 깊은 곳에서 데이터에 접근하려고 할 때, props를 통해 반복적으로 전달하지 않기 위해
    • 사용방법
      1. Context 생성: createContext()를 통해 Context 객체를 생성
      2. Provider 설정: Context의 Provider를 사용해 자식 컴포넌트들이 접근할 수 있도록 데이터를 제공
        • Provider 컴포넌트 내부에서 설정한 state와 그 외 데이터들은 모두 전역으로 관리
      3. useContext로 데이터 접근: useContext를 통해 Context로 제공된 데이터를 원하는 컴포넌트에서 가져와 사용
import React, { useState, createContext, useContext } from 'react';

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

// 2. Provider 컴포넌트
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light'); // 초기 테마 설정

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

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

// 3. useContext로 Context 데이터 사용
function ThemeButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <button onClick={toggleTheme}>
      현재 테마: {theme === 'light' ? '🌞 Light Mode' : '🌜 Dark Mode'}
    </button>
  );
}

// 4. Provider로 컴포넌트 감싸기
function App() {
  return (
    <ThemeProvider>
      <div>
        <h1>Welcome to the Theme Switcher!</h1>
        <ThemeButton />
      </div>
    </ThemeProvider>
  );
}

export default App;