신한투자증권/프로 디지털 아카데미

[신한투자증권 프로디지털아카데미] 클라우드 기반 프론트엔드 개발(React) 프로그래밍 - React Hook 및 상태 관리

쇼파죠하 2025. 6. 9. 23:02

 

신한투자증권 프로 디지털 아카데미 (프디아) 6기 교육 중 배운 내용을 작성한 글입니다

Day 29 (20250609)

 

 


 

배운 개념 정리

 

1. 얕은 비교와 깊은 비교

  • 깊은 비교 : Collection Data(Array, Object 등)의 경우 개별 값들 모두 일일이 비교
  • 얕은 비교 : Collection Data(Array, Object 등)의 경우 참조값만 비교. (일반적인 메모리 주소값)

리액트의 얕은 비교는 객체의 참조주소만 똑같은지 비교하는 방식이다. 리액트에서 얕은 비교를 사용하는 이유는 상태가 변할 때 페이지가 랜더링 되면 다른 상태값들이 일치하는지 체크하게 되는데 깊은 비교를 사용하면 안쪽 depth까지 비교하기 때문에 연산비용이 더 많이 들게 된다. 그래서 빠르게 처리하기 위해서 리액트에서는 랜더링 할 때 얕은 비교를 사용하여 state의 참조값이 다르면 값이 바뀌었다고 인식하고 re-rendering 하게 된다.

 

2. React의 Hook 정리

Hook 설명 
useState 함수형 컴포넌트 내에서 상태 값을 추가하고 관리. 상태를 업데이트하는 함수와 함께 반환.
useEffect 렌더링될 때 특정 값이 변경되면 특정 작업(side effect )을 수행. (ex. fetch, 구독, 타이머 등)
useContext React.createContext()로 만든 Context의 현재 값을 읽음. props drilling 없이 하위로 전달 가능.
useCallback 함수를 메모이제이션하여 의존성 배열 값이 변할 때만 함수가 재생성됨. 성능 최적화 목적.
useMemo 값 자체를 메모이제이션. 연산 비용이 큰 계산을 캐시.
useRef DOM 요소 참조를 유지하거나, 렌더링 간 유지되는 값을 저장하는 데 사용. .current로 접근.
useReducer useState 대안. 복잡한 상태 로직에 사용. (Redux의 리듀서와 유사함)
useImperativeHandle ref를 통해 부모 컴포넌트가 자식 컴포넌트의 함수를 호출할 수 있게 함. forwardRef와 함께 사용.
useLayoutEffect useEffect와 비슷하나, 브라우저가 화면을 그리기 전에 실행됨. DOM 측정 등에 사용.
useId 고유하고 안정적인 ID를 생성. 접근성(accessibility)을 위해 유용.
useTransition 일부 상태 업데이트를 "전환(transition)"으로 처리. 긴급하지 않은 업데이트를 지연시켜 UX 향상.
useDeferredValue 급하지 않은 값 업데이트를 연기. 성능 최적화에 사용.
useActionState Form Action과 함께 사용하는 새로운 Hook. 상태와 pending 상태를 함께 다룸. (이전 useForState)
useOptimistic 낙관적 UI 상태 관리. 성공/실패와 관계없이 UI를 먼저 반영하고, 결과에 따라 수정.
createContext Context 객체를 생성. Provider, Consumer, useContext Hook과 함께 사용.
memo props가 변경되지 않으면 컴포넌트 리렌더링을 방지. 성능 최적화.
lazy 동적 import를 통해 컴포넌트를 코드 분할. <Suspense>와 함께 사용.
startTransition UI 업데이트를 transition으로 처리. 긴급하지 않은 업데이트를 분리하여 성능 최적화. (useTransition Hook과 유사하지만 Hook 외부에서도 사용가능)
use Promise나 Context와 같은 리소스 읽어오는 Hook. 유연한 사용성 제공.
cache 데이터 가져오기(fetching)나 결과를 캐시하는 함수.
<Fragment> 또는 <> 여러 엘리먼트를 그룹화하되, DOM에 불필요한 노드를 추가하지 않음. <></>처럼 사용 가능.
<Suspense> lazy나 use 등으로 비동기 로딩되는 컴포넌트를 fallback UI와 함께 감쌈. 데이터 로딩 중 UI 처리 가능.

 

배웠던 Hook 정리

state가 바뀔 때, props가 바뀔 때 state가 변경되는데,,

  • useState → 컴포넌트 자체에서 관리하는 변수.
  • useRef → 다시 그리지 않는 변수이다.
  • useEffect → state가 변경될 때마다 실행시키는 건 낭비다 → 특정 state가 변경될 때마다 실행할 함수를 정의한다 ( dependency array 가 바뀔 때마다 callbackFn을 실행한다)
  • useMemo → 값을 계산하는 걸 매번 하는 건 낭비다. ( dependency array 가 바뀔 때만 그 함수를 다시 계산한다) 값을 memoization 하는 거 (잠깐 저장해 놓는거다) !!컴포넌트를 memoization 하는거다!!

 

왜 useEffect 있는데 useMemo를 사용해?

useEffect → 함수 실행시키는 데 초점을 맞춤 (state가 변경될때마다 함수 실행)

useMemo → 함수의 return 값을 저장하는데 초점을 맞춤? (state가 변경될때마다 함수 실행)

 

memoization 된 컴포넌트는 부모컴포넌트가 다시 그려져도 자식 컴포넌트를 다시 그리지 않는다 단 전달된 props가 변경될 때만 다시 그린다

HOC(Higher-Order Component)이다.-불필요한 리렌더링을 줄여 애플리케이션 성능 향상.

useCallback : dependency array 가 변할 때마다 함수를 다시 정의한다.

 

 

3. 리액트의 상태 관리

 

 

이 컴포넌트 트리 내에서 자식 컴포넌트끼리 state를 공유할 필요가 있음. (하나의 state를 참조해야하니까)

이 state 관리는 root에서 해야한다

만약 이 something이라는 state를 F에서 관리한다고 한다면 H라는 컴포넌트에 그 state를 전달할 방법이 없다.

부모 컴포넌트가 자식 컴포넌트에게 전송할 수 있다(props로)

근데 자식 컴포넌트가 관리하고 있는 state를 부모 컴포넌트에 전달할 수 있는 방법은 없다.

공통의 조상 컴포넌트 내에서 그 state에서 관리해줘야 한다.

 

4. 상태관리와 Context API를 사용해야 하는 이유

 

 

상태 관리 

 

모든 컴포넌트는 트리(tree) 구조에서 루트(root) 컴포넌트를 가지며, 이 루트 컴포넌트에서 모든 하위 컴포넌트를 렌더링 한다

컴포넌트 간의 데이터 전달은 상위 컴포넌트에서 하위 컴포넌트로 props라는 이름으로 전달한다

리액트에서 상태(state)란 컴포넌트 내부에서 관리되는 값으로, 사용자의 입력, 서버로부터 받은 데이터, 다른 컴포넌트와의 상호작용 등으로 인해 동적으로 변할 수 있는 값이다

리액트에서 상태관리는 컴포넌트 간의 데이터 전달과 관리를 의미함

 

 상태가 여러 컴포넌트에서 공유되어야 하는 경우, 상태를 관리하는 컴포넌트를 중심으로 props로 상태값을 전달하는 방식은 번거롭고 복잡해질 수 있음 -> Props Drilling 문제 발생.

 

Props Drilling

 

Props Drilling은 부모 컴포넌트에서 데이터를 전달받은 자식 컴포넌트가, 다시 하위 컴포넌트로 데이터를 전달해야 하는 상황으로 매번 Props를 전달해야 하기 때문에 코드도 복잡해지고 유지 보수도 힘들어진다.

 

 

 

Context API 사용

 

Context API는 리액트에서 상태(state)를 전역적으로 관리하기 위한 방법 중 하나

React의 createContext 메소드를 사용하여 생성된 객체로, 이를 이용하면 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 필요 없이, 어떤 컴포넌트에서든 값을 공유할 수 있음

 

Context API는 Provider와 Consumer를 제공하여, Provider로 값을 설정하고 Consumer로 값을 가져와 사용할 수 있는데 Provider로 값을 설정하면, 하위 컴포넌트에서 Consumer를 사용하여 값을 가져올 수 있다

Provider는 value prop을 사용하여 값을 설정하며, Consumer는 함수 자식(child)을 받아서 그 함수 내부에서 값을 가져올 수 있다

  • createContext() 함수를 호출하여 Context 객체를 생성 -> 이 Context 객체는 Provider와 Consumer로 구성됨
  • Provider는 Context로 전달할 값을 설정하는 컴포넌트 ->  이 값은 Provider 컴포넌트의 props로 전달됨 -> 이렇게 설정된 값을 Consumer에서 사용할 수 있음
  • Consumer는 Context 값을 사용하는 컴포넌트 -> 이 컴포넌트에서는 Context 객체를 가져와서 값을 사용함
  • useContext는 React 16.8 이상 버전에서 Context 값을 사용하는 훅으로 -> Consumer과 동일하게, 해당 훅을 사용해 Context 객체를 가져와서 값을 사용함

 

Context API의 주의할 점

 

1. Provider의 컴포넌트 트리의 상위에서 상태 변경이 일어나면 하위에 Context를 구독하고 있는 모든 컴포넌트가 리렌더링 된다

2. 특정 Context.Provider에 의존하기 때문에 컴포넌트 간 결합도가 증가하여 재사용이 어려워진다.

 

 

 

상태 관리를 위한 다양한 라이브러리

 

cf . 리액트 상태 관리를 위한 라이브러리들이 많이 존재하는데 각각 특수한 분야에 대해 전문적으로 상태를 관리한다

  • Zustand 모듈 상태를 전문적으로 다룸
  • Recoil data-flow 그래프(말 그대로 데이터 흐름을 보여주는 그래프)를 사용하는 실험적인 라이브러리
  • Jotai 연산된 값(computed values)과 비동기 액션에 최적화 되어있음
  • Valtio mutation-style API를 제공하기 위해 프록시를 사용함

 

 

- Redux를 사용해야 할 때

  • UI 레이어와 분리된 복잡한 상태 관리 로직 작성이 필요할 때
  • Redux 미들웨어 기능을 활용하거나 복잡한 비동기 작업으로 액션 전달에서 추가적인 로직이 필요할 때
  • 여러 위치에 대량의 상태 값이 존재하고 업데이트 로직이 복잡하거나 거대한 코드베이스를 여러 사람이 작업할 때
  • side effect, memoization, data serialization 등 강력한 기능이 필요할 때

 

- Context API를 사용해야 할 때

  • 단순 prop-drilling을 피하는 것이 목적일 때
  • 적당히 복잡한 컴포넌트에서 단순 값을 전달하는 파이프가 필요할 때
  • 리액트 컴포넌트 트리 안에서 전역 데이터를 공유해야할 때

context 흐름 정리

 

 

4. React bootstrap 사용

 

리액트 부트스트랩은 그냥 이용하기만 하면 된다.

https://react-bootstrap.github.io/docs/getting-started/introduction/

 

Introduction | React Bootstrap

Learn how to include React Bootstrap in your project.

react-bootstrap.netlify.app

 

먼저 위 사이트에 들어가면 Getting started를 누르면 어떻게 설치하고 어떻게 사용하는지 자세하게 나와있다. 

npm install react-bootstrap bootstrap

 

먼저 부트스트랩을 설치해주고

보통 App.jsx 파일에서 많이 쓰는데

 

import 'bootstrap/dist/css/bootstrap.min.css';

 

로 import 해주면 된다

 

 

메뉴를 보면 Components 들, Forms 들 등등 다양하게 이용할 수 있는 요소를 클릭하고,

거기에 있는 코드를 사용하기만 하면 된다.

 

 

 

5. Local storage 저장

 

새로 고침하면 데이터가 사라지지 않게 이 값들을 로컬 스토리지나 세션 스토리지에 저장해놓고 불러와서 이용할 수 있다.

 

 

  로컬 스토리지 쿠키 세션
저장 위치 클라이언트 클라이언트 서버
저장 용량 5~10MB 4KB 서버설정에 따라 다름
유효 기간 영구적
(사용자가 명시적으로 삭제하지 않는 한 유지)
설정 가능
(세션 쿠키는 브라우저 종료 시 삭제)
브라우저 종료 시 삭제
(서버에서 설정 가능)
데이터 전송 서버로 전송되지 않음 서버로 자동 전송 서버에서 관리,
클라이언트에는 세션 ID만 저장
보안 클라이언트 자바스크립트로 접근 가능, 보안 취약 HttpOnly, Secure 옵션으로 보호 가능 서버에서 관리, 비교적 안전
사용 목적 클라이언트 측 영구 데이터 저장 세션 관리, 인증 정보 유지, 상태 저장 사용자 인증 정보 등 일시적 상태 저장

 

F12의 Application 클릭해보면 사이트에 저장되어 있는 Local storage, Session storage, Cookies 정보 확인할 수 있다

 

이것도 저장할 수 있는 방법이 많기 때문에 쓰는 사용목적에 따라서 잘 골라서 사용하면 좋을 것 같다.

 

나는 연습문제 푸는 중에 Local storage에 저장하였다

 

 

참고 자료

 

 

 

Context – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

 

 

 

 

 

Context API를 사용한 상태관리

Context API는 리액트에서 상태(state)를 전역적으로 관리하기 위한 방법 중 하나입니다. 이를 이용하면 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 필요 없이, 어떤 컴포넌트에서든 값을

velog.io

 

 

[React] 리액트에서의 상태 관리, 무엇이고 어떻게 해야할까

목차1. 서문2. React에서 상태를 관리하는 방법- 기본 상태 관리 방법- 내부 기능 훅 사용하기- 외부 라이브러리 사용하기3. 상태 관리를 "잘"하는 방법1.  서문최근 공개된 Figma Config 2024에도 나왔고

jlee0505.tistory.com

 

 

[React] 전역 상태 관리

🐗 전역 상태 관리의 필요성 일반적으로 React에서는 데이터는 부모로부터 props를 통해 전달된다. 그러나 컴포넌트를 나누다보면 하나의 어플리케이션 안에 여러 컴포넌트에 전달해줘야 하는 경

velog.io

 

 

React 상태 관리 라이브러리 비교하기 - bandal.dev

React는 컴포넌트 기반의 라이브러리여서, 작은 컴포넌트들이 모여서 복잡한 구조를 구성하게 됩니다. 앱의 규모가 커질수록 상태관리가 점점 복잡해져서 컴포넌트 간의 상태를 전달할 때 Props Dr

bandal.dev

 

[React.js] 로컬 스토리지(LocalStorage)에 내용을 저장하고, 전역 상태 관리 라이브러리(Redux)와 동기화

로컬 스토리지(LocalStorage)에 내용을 저장하고, 전역 상태 관리 라이브러리(Redux)와 동기화 하는 방법들어가며리액트(React.js)에서 특정 변수를 로컬 스토리지(Local Storage)에 저장하고, 전역 상태 관

dev-astra.tistory.com

 

반응형