[LG CNS AM INSPIRE CAMP 1기] React의 주요 Hook들의 이해와 활용 useState, useReducer, useMemo, useCallback, useContext

2025. 1. 6. 15:06·LG CNS AM CAMP 1기
🔑한번 보고 모르겠으면, 두번 보고, 세번 보고, 누가 이기나 해보자

💡  useState로 Counter 구현하기


📃 useState를 사용하여 간단한 Counter 기능을 구현한 후, 이를 기반으로 useReducer와의 차이점을 이해해 보겠습니다

💻useState를 활용한 Counter 구현

import React, { useState } from 'react'


const Counter = () => {
  const [count, setCount] = useState(0);
  const changeCount = e => setCount(count + Number(e.target.innerText));

  return (
    <>
      <div>현재 카운터 값은 <b>{count}</b> 입니다</div>
      <div>
        <button onClick={changeCount}>+1</button>
        <button onClick={changeCount}>-1</button>
      </div>
    </>
  )
}

const App = () => {
  return (
    <>
      <Counter />
    </>
  )
}

export default App

❗ 현재 구현은 버튼의 텍스트가 반드시 숫자여야 하는 제한사항이 있습니다. 문자열 형태의 버튼 텍스트를 사용할 경우 정상적인 동작을 보장할 수 없으므로, 아래와 같이 개선된 버전을 구현해보겠습니다 

 

💻문자열 텍스트 대응 (useState로 함수 분리)

import React, { useState } from 'react'

const Counter = () => {
  const [count, setCount] = useState(0);
  const countPlus = () => setCount(count + 1); 
  const countMinus = () => setCount(count - 1); 

  return (
    <>
      <div>현재 카운터 값은 <b>{count}</b> 입니다</div>
      <div>
        <button onClick={countPlus}>하나 더하기</button>
        <button onClick={countMinus}>히나 빼기</button>
      </div>
    </>
  )
}

const App = () => {
  return (
    <>
      <Counter />
    </>
  )
}

export default App

 

⬆️ 각각의 동작을 독립된 함수로 분리함으로써, 버튼 텍스트와 상관없이 안정적인 동작을 보장할 수 있습니다. 하지만 나누기, 곱하기, 세제곱 등등 기능이 추가되면 컴포넌트 내에 함수도 계속해서 정의해줘야할 것 입니다

💡 useReducer로 Counter 구현하기


📃 useReducer는 복잡한 상태 로직을 관리하기 위한 useState의 대안입니다. 상태 업데이트 로직을 컴포넌트에서 분리하여 관리할 수 있으며, 여러 상태 전환을 체계적으로 관리할 수 있습니다

https://www.jstopics.com/reactjs/usereducer-with-typescript

💻CODE

import React, { useReducer } from 'react'

function reducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <>
      <div>현재 카운터 값은 <b>{state.count}</b> 입니다</div>
      <div>
        <button onClick={() => dispatch({ type: 'INCREMENT' })}>하나 더하기</button>
        <button onClick={() => dispatch({ type: 'DECREMENT' })}>히나 빼기</button>
      </div>
    </>
  )
}

const App = () => {
  return (
    <>
      <Counter />
    </>
  )
}

export default App

⬆️ 사실 단순한 카운터의 경우 useState로도 충분하나, 상태 관리 로직이 복잡해질 경우 useReducer를 활용하면 더욱 체계적인 상태 관리가 가능합니다. 또한 reducer 함수를 별도로 정의함으로써 로직의 재사용성이 향상됩니다

 

💡 useMemo 란


📃 useMemo는 메모이제이션을 통해 성능을 최적화하는 Hook입니다. 특정 값이 변경될 때만 계산을 수행하도록 하여 불필요한 연산을 방지합니다. 이렇게만 설명하면, 무조건 사용하는 것이 좋지 않을까? 라고 생각할 수 있지만, 결국 Memo, useCallback 누군가가 정의해놓은 함수라는 것 입니다. 즉 메모리를 사용하고 비교 연산이 있다는 것이죠. 그래서 무분별하게 Memo와 Callback을 사용하는 것은 오히려 성능을 저하시킵니다

💻useMemo 훅 사용

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

const ExpensiveCalculation = ({ number }) => {
  const calc = useMemo(() => {
    console.log('복잡한 계산 수행...');
    return number * 2;
  }, [number]);

  return <div>계산 결과: {calc}</div>;
};

const App = () => {
  const [number, setNumber] = useState(0);

  return (
    <>
      <button onClick={() => setNumber(number + 1)}>증가</button>
      <ExpensiveCalculation number={number} />
    </>
  );
};

export default App;

⬆️ useMemo를 통해 의존성 배열의 값이 변경될 때만 계산이 실행되어 성능을 최적화할 수 있습니다. 하지만 핵심은 위와 같은 간단 연산은 useMemo를 사용하는 것이 오히려 성능 저하를 불러일으킵니다

 

💡 useCallback 이란


📃 useCallback은 컴포넌트의 성능을 최적화하기 위한 Hook으로, 메모이제이션된 콜백 함수를 반환합니다. 특히 자식 컴포넌트에 함수를 props로 전달할 때 불필요한 렌더링을 방지하는데 효과적입니다

https://viniciuspetrachin.medium.com/optimizing-react-native-performance-with-usecallback-bdb6d801c9cf

💻useCallback 사용 사례

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

const Child = React.memo(({ onClick }) => {
  console.log('Child 컴포넌트 렌더링');
  return <button onClick={onClick}>자식 컴포넌트 버튼</button>;
});

const App = () => {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  // useCallback을 사용하지 않은 경우
  // const increment = () => setCount(count + 1);

  // useCallback을 사용하여 함수 메모이제이션
  const increment = useCallback(() => setCount((prev) => prev + 1), []);

  return (
    <div>
      <div>
        <button onClick={increment}>카운트 증가</button>
        <p>현재 카운트: {count}</p>
      </div>
      <div>
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
          placeholder="텍스트 입력"
        />
      </div>
      {/* 자식 컴포넌트에 메모이제이션된 콜백 전달 */}
      <Child onClick={increment} />
    </div>
  );
};

export default App;

⬆️ 적용 전

  • increment 함수가 App 컴포넌트가 리렌더링될 때마다 새로운 함수 인스턴스로 생성됩니다.
  • 이는 Child 컴포넌트가 불필요하게 리렌더링되는 원인이 됩니다.

⬆️ 적용 후

  • increment 함수는 메모이제이션되어 동일한 함수 인스턴스를 재사용합니다.
  • 따라서 Child 컴포넌트는 리렌더링되지 않습니다.

💡 useContext 란


📃 useContext는 React 컴포넌트 트리 전체에 데이터를 공유할 수 있게 해주는 Hook입니다. Context API를 통해 prop drilling을 방지하고, 전역 상태를 효율적으로 관리할 수 있습니다.

💻useContext 사용 사례 (Dark 모드)

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

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

const ThemeProvider = ({ children }) => {
  const [isDarkMode, setIsDarkMode] = useState(false);

  const toggleTheme = () => setIsDarkMode(!isDarkMode);

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

const ThemeToggleButton = () => {
  const { isDarkMode, toggleTheme } = useContext(ThemeContext);

  return (
    <button onClick={toggleTheme}>
      {isDarkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode'}
    </button>
  );
};

const AppContent = () => {
  const { isDarkMode } = useContext(ThemeContext);

  return (
    <div
      style={{
        backgroundColor: isDarkMode ? '#333' : '#FFF',
        color: isDarkMode ? '#FFF' : '#000',
        minHeight: '100vh',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        flexDirection: 'column',
      }}
    >
      <h1>{isDarkMode ? 'Dark Mode' : 'Light Mode'}</h1>
      <ThemeToggleButton />
    </div>
  );
};

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

export default App;

 

Light Mode
Dark Mode

⬆️ useContext를 활용하면 컴포넌트 계층 구조의 모든 레벨에서 데이터에 직접 접근할 수 있어 props 전달 과정을 단순화할 수 있습니다. 이는 특히 테마, 인증 상태, 언어 설정과 같은 전역적으로 관리되어야 하는 상태에 매우 효과적입니다.

 

📝 SUMMARY


📌 useState는 React에서 상태를 관리하는 기본적인 Hook입니다. 간단한 상태 변경에는 적합하지만, 상태 로직이 복잡해지면 useReducer를 고려할 수 있습니다

📌 useReducer는 복잡한 상태 관리 로직을 다룰 때 유용합니다. 상태 업데이트를 dispatch를 통해 처리하고, 상태 변경 로직을 reducer 함수로 분리하여 코드의 재사용성을 높이고 상태 변화를 더 체계적으로 관리할 수 있습니다

📌 useMemo는 값의 변화에 따라 계산을 메모이제이션하여 불필요한 연산을 방지하는 Hook입니다. 성능 최적화가 필요한 경우에 유용하지만, 간단한 계산에는 오히려 성능 저하를 유발할 수 있습니다

📌 useCallback은 함수의 메모이제이션을 통해 불필요한 렌더링을 방지합니다. 주로 자식 컴포넌트에 콜백 함수를 전달할 때 성능 최적화에 사용됩니다.

📌 useContext는 전역적으로 관리되는 상태를 React 컴포넌트 트리에서 공유할 수 있도록 해주는 Hook입니다. Prop drilling을 방지하고, 테마나 인증 상태와 같은 전역적인 상태 관리에 효과적입니다.

저작자표시 비영리 변경금지 (새창열림)
'LG CNS AM CAMP 1기' 카테고리의 다른 글
  • [LG CNS AM INSPRIRE CAMP 1기]순차지향, 절차지향, 객체지향: 프로그래밍 패러다임 완벽 이해하기
  • [LG CNS AM INSPIRE CAMP 1기] AMaze 간단한 지식 공유 웹 애플리케이션 구현 - 프론트엔드를 마치며
  • [LG CNS AM CAMP 1기] 12/23~01/03 2주간의 학습 내용 정리
  • [LG CNS AM INSPIRE CAMP 1기] - [React] Ref, 리엑트 생명주기 Lifecycle 뿌수기 🔨
Jelong
Jelong
커스텀 웹: https://jaehong-park.com Github: https://github.com/qkrwoghd04
  • Jelong
    24/7 Developer's Note
    Jelong
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Software Engineering
      • Ubuntu
      • Network
      • JavaScript
      • Web
      • Interaction Design
      • React Native
      • React
      • Algorithm
      • Java
      • Database design
      • IT Trend
      • TroubleShooting
      • AWS
      • Interview
      • LG CNS AM CAMP 1기
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    블랙 박스 테스트
    java
    JS
    AWS
    javascript
    데이터 구조
    GPT-4
    미니넷
    frontend
    ChatGPT
    BST
    html
    typescript
    prototyping
    Queues
    알고리즘
    자바
    소프트웨어 공학
    expo
    알고리즘 분석
    티스토리챌린지
    이진트리
    generic
    mininet
    화이트 박스 테스트
    자바스크립트
    오블완
    React
    css
    heap
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
Jelong
[LG CNS AM INSPIRE CAMP 1기] React의 주요 Hook들의 이해와 활용 useState, useReducer, useMemo, useCallback, useContext
상단으로

티스토리툴바