📂 오늘 배운 내용
1. 지난 시간 기본적인 Hook들(useState, useRef, useEffect)에서 더 나아가 useMemo, useCallbak, useReducer 배움
- useEffect vs useMemo vs useCallback 😵💫
- useState vs useReducer 🤢
2. react-hook-form 라이브러리
Hooks 사용 규칙
hooks의 등장으로 함수형 컴포넌트에서도 상태관리 (state)와 생애주기(lifecycle) 사용할 수 있게 되었다.
- Hook은 함수형 컴포넌트/ 커스텀 hook의 최상위 단계에서만 호출해야함
- 리액트는 Hook 호출 순서 기반으로 상태와 렌더링을 관리하기 때문!
- 조건문이나 반복문 안에서 hook 호출하면, 렌더링 시마다 호출 순서가 달라질 수 있어 리액트가 상태를 제대로 추적하지 못함
- hook은 무조건 Import 후 사용
Hooks 종류
• `useState()` : 상태 관리
• `useRef()` : 1. 원하는 DOM 요소 직접 접근 2. 렌더링 되어도 값을 유지하고 싶은 변수가 있을 때 로컬 변수로 사용
• `useEffect()` : 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정
• `useMemo()` : useEffect와 비슷하게 생겼지만 '값'을 저장하여 재사용 → 연산 최적화
• `useCallback()` : 함수를 저장(메모이제이션)하여 렌더링 최적화
• `useReducer()` : 복잡한 컴포넌트 상태 로직을 reducer 함수를 통해 관리
• `useContext()` : 리액트에서 전역적으로 접근 가능한 데이터나 함수를 관리하고, 필요한 컴포넌트에서 그 값을 바로 가져와 사용할 수 있게 도와주는 훅
공식문서 더 많은 Hooks 살펴보기 (클릭 시 이동)
useEffect
1. 컴포넌트가 렌더링될 때마다 특정 작업을 실행할 수 있는 Hook (mount, unmount, update시마다 실행 가능)
2. dependency array에 따른 기능 차이 알아두기
useRef
1. 함수형 컴포넌트에서 DOM 요소에 직접 접근하는 법: ref 객체 만들어 `ref.current`값으로 원하는 DOM 요소 직접 선택 가능
2. 로컬 변수로 사용 : 렌더링되어도 값을 유지하고 싶은 변수가 있다면 ref.current 사용
useMemo
const memoizedValue = useMemo(callback, depencency);
렌더링 과정에서 두번째 인자로 받은 의존성 배열 내 값이 바뀌는 경우에만,
첫번째 인자로 받은 콜백함수를 실행해 구한 값을 반환한다.
# useMemo 사용하는 이유
export default function UseMemo1() {
const [number, setNumber] = useState(0);
const [inputValue, setInputValue] = useState('');
// [useMemo 사용 전]
// 문제: input 스테이트가 변경될 때도 연산이 이루어짐 > calc() 호출 중
const calc = () => {
console.log('계산 중...');
return number * 2;
};
// [useMemo 사용 후]
// 해결: 특정 값이 바뀔 때만 calc() 함수 호출되도록
// number 값이 변경될 때만 함수를 재실행하고 값을 저장
const calc2 = useMemo(() => {
console.log('계산 중...2');
// return 이후의 number * 2값이 Memoization 됨
return number * 2;
}, [number]);
return (
<>
<input
type='text'
onChange={(e) => setInputValue(e.target.value)}
value={inputValue}
/>
<button onClick={() => setNumber(number + 1)}>+1</button>
<p>number: {number}</p>
<p>clac: {calc()}</p>
<p>clac2: {calc2}</p>
</>
);
}
함수형의 경우 호출 시 컴포넌트 렌더링되어 함수 내부 모든 변수 초기화
함수 재호출은 성능에 안 좋아서 다른 곳에 calc(3,5)를 다른 곳에 저장해두고 리렌더링될 때 결괏값만 가져옴
# useEffect vs. useMemo
렌더링될 때마다 메모리 값을 가져와서 씀
useMemo를 사용해서 결과값 (korea) 메모리에 저장한 뒤, 함수를 다시 실행하는 것이 아니라 결과값만 가져와서 재사용
useEffect와 생김새는 비슷하지만 연산 최적화를 위해 사용, useEffect와 다르게 '값'을 저장해주는 hook
함수형 컴포넌트 내부에서 발생하는 연산 최적화 Hook
리렌더링 과정에서 특정 값이 바뀔 때만 연산
JavaScript Primitive vs. Object Type
- 원시 타입: 비교할 때 값을 비교함
- 객체 타입: 값이 아닌 메모리에 저장된 주소를 비교함
따라서
객체 location을 의존성배열로 넣으면 렌더링될 때마다 다른 값으로 인식하는 문제 (원래 의도랑 다름)
UseMemo를 사용해서
컴포넌트는 함수기 때문에 렌더링 됐을 때, 렌더링 될 때마다 다른 메모리 주소값으로 저장됨 -> 해결: useMemo
useMemo 객체 저장 시 유용하게 사용될 수 있음
useCallback
렌더링 최적화에 사용되는 Hook API
값이 아닌 함수를 메모리에 저장함
useMemo(값 저장)랑 useCallback(함수 저장) 비슷하게 생김
useReducer
- state 변경 시 복잡한 로직을 사용하고 싶을 때 변경 로직을 함수로 따로 만들어서 관리
- useState로 복잡한 로직 해결하기 힘들때 사용
- 예를 들어 쇼핑몰 장바구니처럼 아이템 추가, 삭제, 수량 변경 등 여러 상태 변경 로직이 필요한 경우
useState는 2가지 요소이지만 useReducer는 4가지 요소를 가짐 :
- `state` : 상태
- `dispatch` : 상태를 변경시켜달라는 요구 : 함수라고 생각하면됨
- `action`
- dispatch의 인자(문자열 또는 객체 = 값) -> reducer의 두번째 인자로 전달
- `dispatch`의 내용. 실제 요청을 보낼 때 사용 (예: 기존 상태에서 1 빼주세요)
- `reducer`: : 함수(현재 state, action)
- 실제로 상태를 업데이트 시켜주는 매개체
reducer, dispatch는 함수! dispatch, action은 세트
dispatch에 action을 담아 reducer의 두번째 인자로 전달
- reducer의 첫번째 인자 = prevNumber = 이전 스테이트
- dispatch: 요구를 전달하는 함수 dispatch(action) => reducer의 두번째 인자 (action)으로 요구를 전달
useState() vs useReducer()
상황에 따라 적절한 Hook 선택
- `useState()`: state 단순
- `useReducer()`: state 복잡 (객체, 배열 같이 하위 요소 많은 경우)
useContext
상태 관리를 위한 함수
상태를 전역적으로 관리
전역 상태관리는 Redux (어려움 🤢 다음주에 배움)
custom Hook
- 보통 `hooks/` 폴더 내부에서 관리
- 내부에서 react Hook(useState, useEffect 등)을 반드시 사용해야만 custom hook이라 부를 수 있음
- 사용하지 않으면 그냥 일반 함수
# 예시1 `useTitle`
import { useEffect } from "react";
export function useTitle(title) {
useEffect(() => {
document.title = title;
}, [title]);
}
useTitle("Home Page");
- 리액트는 SPA 특성을 가지므로 html이 하나(index.html)
- 페이지 이동 시 브라우저의 페이지 제목(title) 변경해야 할 때 사용
# 예시2 : `useToggle`
- 상태값을 true/false로 전환하는 커스텀 훅
- 체크박스, 모달창 열기/닫기, 다크모드 활성화 등 상태 전환이 필요한 작업에서 유용함
useForm (react-hook-form 라이브러리)
# 설치
npm i react-hook-form
폼의 상태 관리와 유효성 검증이 더 쉬워지는 라이브러리
# 주요 키워드
`register( )`
<input {...register("username", { required: "Username is required" })} />
- name 속성을 대신하는 register.
- 이 함수를 통해 입력 요소에 유효성 검사 규칙 설정할 수 있음!
- register 함수를 통해 반환된 객체를 spread 연산자로 입력 필드에 전달하도록 요구
`handleSubmit( )`
- 폼 제출 처리용 함수
- 이 함수에 전달된 콜백은 유효성 검사를 통과한 데이터를 인자로 받아 실행함
`watch`: 특정 폼 필드값 실시간 관찰하는 함수
`formState`
- 폼 상태 나타내는 객체
- 예: `errors` `isValid` `isDirty` `isSubmitted` 등 상태 포함
# 예제
정리
1. useEffect, useMemo, useCallback
useEffect | useMemo | useCallback | |
주요 목적 | - 값의 변경 관찰 - 부수 효과(side effect) 처리 |
- 값의 저장, 재사용 - 불필요한 연산 방지, 성능 최적화 |
- 함수 저장 - 렌더링 최적화 |
사용 예시 | - 데이터 가져오기 (API 호출) - DOM 조작 - 이벤트 리스너 등록/해제 |
- 복잡한 계산 - 배열이나 객체의 정렬/필터링 |
- 이벤트 핸들러 메모이제이션 - props로 전달되는 콜백 함수 |
특징 | - 상태/Props 변경 시 렌더링 발생 - 의존성 배열에 명시된 값이 변경될때만 콜백 실행 |
의존성 배열 내 값이 변경되지 않으면 저장된 결과값 반환 | 의존성 배열 내 값이 변경되지 않으면 저장된 함수 반환 |
반환값 | 없음 | 연산 결과값 반환 | 저장(메모이제이션)된 함수 반환 |
성능 | 부수 효과 많아지면 렌더링 속도 느려질 수 있음 | 복잡한 연산 필요 이상으로 반복 실행하지 않도록 최적화 | 불필요한 함수 재생성을 방지하여 렌더링 성능 개선 |
2. useState, useReducer
둘 다 컴포넌트 내부에서만 동작
useState | useReducer | |
주요 목적 | 간단한 상태 관리 | 복잡한 상태 로직 관리 |
사용 예시 | - 입력 필드 값 관리 - 단순 카운터 기능 |
- 여러 상태 값 관리 - 상태 간 의존성 높은 경우 - 상태 변경 로직 분리할 때 |
특징 | - 간단하고 빠른 구현 - 상태 초기값 설정 가능 |
- reducer 함수와 dispatch를 통해 상태 변경 로직 분리 - 상태 변경 로직 재사용 가능 |
반환값 | [상태값, 상태 변경 함수] | [상태값, dispatch 함수] |
💡 회고
1. 폼 라이브러리의 신세계 :
폼 라이브러리 쓰면 수동으로 ref 설정 안 해줘도 좀 더 간편하게 폼 처리가 가능하다!!! 신세계다!
`register`를 사용하면 입력 필드에 `ref`가 자동으로 설정되어, 별도의 `useRef`를 사용하지 않아도 내부적으로 DOM 조작이 가능하다. 입력값 없을 때 인풋창에 포커스 효과 줄 때 좋음.
+ 포커스 효과 주는게 alert 창 띄우는 것보다 사용자 경험에 좋다고해서 다음 프로젝트때는 적극적으로 활용할 계획이다.
2. 어질어질 useReducer:
useReducer가 redux와 흐름이 비슷한데 더 쉬운 버전이라고 한다. useReducer도 복잡한데, redux는 도대체 상태가 얼마나 복잡할 때 쓰는 건지 상상하기 싫다...🤮
🌐 참고
서울시 청년취업사관학교x코딩온 웹 풀스택 과정
24. react-hooks
24.hooks-pracitce
'Today I Learned > SeSAC 웹 2기' 카테고리의 다른 글
React 상태관리 ContextAPI와 Redux | 13주차(1)하 (0) | 2025.01.23 |
---|---|
React Router | 13주차(1)상 (1) | 2025.01.23 |
React Style 적용 방법 | 12주차 (2) (0) | 2025.01.14 |
React useRef, Lifecycle(useEffect) | 12주차 (1) (0) | 2025.01.14 |
React Event Handling | 11주차 (3) (0) | 2025.01.14 |