🧩 7. React.memo – 컴포넌트 메모이제이션
정의
React.memo는 컴포넌트를 메모이제이션하여,
props가 바뀌지 않으면 리렌더링을 막아주는 고차 컴포넌트(HOC) 이다.
즉, 같은 props로 여러 번 호출되어도 이전 결과를 재사용하여 렌더링을 스킵할 수 있다.
--> 부모가 자식에게 props 전달 시 , props 값이 변경된 경우에만 리렌더링하게 하고 싶을 경우에 사용한다.
예제
// App.js
import React, { useEffect, useState, useCallback } from "react";
import Child from "./Child";
function App() {
const [count, setCount] = useState(0);
console.log("부모 컴포넌트 렌더링");
return (
<div>
<h1>부모 컴포넌트</h1>
<p>Count: {count}</p>
<button onClick={() => setCount((prev) => prev + 1)}>부모버튼</button>
<Child />
</div>
);
}
export default App;
// Child.js
function Child() {
console.log("자식 컴포넌트 렌더링");
return (
<div style={{ border: "10px solid red", marginTop: "50px" }}>
<h1>자식 컴포넌트</h1>
</div>
);
}
export default Child;
- 부모 컴포넌트의 버튼을 누를 때마다 child 컴포넌트도 리렌더링 된다.
- 자식 컴포넌트의 리렌더링을 막기위해 Child에 React.memo를 해주면 된다.
export default React.memo(Child);
왜 자식까지 계속 렌더링되는지?
지금은 Child 컴포넌트가 props를 안 받고 있어서 리렌더가 안 되어도 될 것 같지만,
React는 부모가 리렌더링되면 기본적으로 자식도 다 리렌더링이 된다.
🧩 useReducer – 복잡한 상태 로직을 관리할 때
정의
useReducer는 useState보다 복잡한 상태 전이를 필요로 할 때 사용하는 훅이다.
Redux와 유사하게 동작하며, state와 dispatch 함수를 반환한다.
문법
const [state, dispatch] = useReducer(reducer, initialState);
예제
import { useState, useReducer } from "react";
//reducer 함수: 현재 상태와 액션을 받아 새로운 상태를 반환
const reducer = (state, action) => {
console.log("리듀서 실행!", state, action);
switch (action.type) {
case "PLUS":
return state + 1;
case "MINUS":
return state - 1;
default:
return state;
}
};
const UseReducer = () => {
// const [count, setCount] = useState(0);
const [count, dispatch] = useReducer(reducer, 0);
const plusHandler = () => {
// setCount(count + 1)
dispatch({ type: "PLUS" });
};
const minusHandler = () => {
// setCount(count - 1)
dispatch({ type: "MINUS" });
};
return (
<div style={{ textAlign: "center" }}>
<h1>{count}</h1>
<button onClick={plusHandler}>더하기</button>
<br />
<br />
<button onClick={minusHandler}>빼기</button>
</div>
);
};
export default UseReducer;
const [count, dispatch] = useReducer(reducer, 0);
- 이 줄은 마치 useState의 const [count, setCount] = useState(0) 과 비슷하지만,
상태 변경 로직을 외부 함수(reducer)로 분리한 점이 다름
특징
- state가 객체 또는 복잡한 구조일 때 유리함
- 여러 상태를 하나의 reducer 함수로 관리 가능
🧩useContext – Context API와 함께 전역 상태 공유
정의
- useContext는 Context 객체의 현재 값을 반환한다.
- 깊은 컴포넌트 트리에서도 데이터를 직접 전달할 수 있다.
문법
const value = useContext(MyContext);
사용 흐름
- React.createContext()로 context 생성
- .Provider로 값을 전달
- 자식 컴포넌트에서 useContext로 값 조회
import React, { createContext, useState, useContext } from "react";
// 컨텍스트 생성
const ThemeContext = createContext();
function App() {
const [theme, setTheme] = useState("light");
return (
// 컨텍스트 제공
<ThemeContext.Provider value={{ theme, setTheme }}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
// useContext를 통해 컨텍스트 값 사용
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Current Theme: {theme}
</button>
);
}
export default App;
| 단계 | 설명 |
| createContext() | ThemeContext 생성 (테마 저장소 만들기) |
| ThemeContext.Provider | 공급자 역할, 하위 컴포넌트에게 theme와 setTheme을 제공 |
| useContext(ThemeContext) | 하위 컴포넌트에서 값을 꺼내 쓰기 |
| 버튼 클릭 → setTheme | 현재 테마를 토글함 (light <-> dark) |
주의사항
- Provider로 감싸지 않으면 undefined가 반환됨
- 값 변경 시 Provider 하위 컴포넌트 전부 리렌더링됨 → useMemo로 value 최적화 필요하다.
🧩 Custom Hook – 로직 재사용의 정석
정의
Custom Hook은 use로 시작하는 함수 이름으로, 다른 Hook을 조합하여 재사용 가능한 로직 단위를 만든 것이다.
예제: useFetch
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Fetch 실패');
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
예제 : useInput.js 파일 생성 후 기존 로직을 대체
// useInput.js import
import { useInput } from "./useInput";
function App() {
// 리턴 값에 맞춰서 inputValue, handleChange 작성
const [inputValue, handleChange] = useInput("홍길동");
const handleSubmit = () => {
if (inputValue !== "") {
window.alert("전송 완료");
}
};
return (
<div>
<input
type="text"
value={inputValue}
onChange={handleChange}
placeholder="텍스트를 입력하세요"
/>
<button onClick={handleSubmit}>전송</button>
</div>
);
}
export default App;
Hook과 클로저(Closure)의 관계
클로저란?
클로저는 자바스크립트에서 외부 함수의 실행 컨텍스트가 종료된 이후에도
해당 함수의 변수(스코프)를 참조할 수 있는 내부 함수를 의미한다.
Hook은 클로저를 활용한 대표적 사례이다.
React Hook 내부에서 사용하는 상태나 함수들은 사실상 클로저로 관리된다고 한다.
예를 들어 useState로 만든 상태는 렌더링 당시의 스코프에 닫힌 상태를 참조한다.
상태 업데이트와 리렌더링
setState 함수를 호출하면 상태가 업데이트되며, React는 해당 컴포넌트를 리렌더링한다.
이때, useState는 클로저를 통해 이전 상태를 기억하고 있으므로, 새로운 상태를 기반으로 컴포넌트를 다시 렌더링할 수 있는 것이다.
HOC 패턴(Higher-Order Component)
HOC이란?
HOC는 컴포넌트를 인자로 받아 새로운 기능을 가진 컴포넌트를 반환하는 함수이다.
즉, 컴포넌트를 매개변수로 받아, 컴포넌트를 반환하는 함수형 디자인 패턴이다.
특징
- 재사용성: 로직을 추상화하여 여러 컴포넌트에 동일한 기능을 주입
- 컴포넌트 합성: 기존 컴포넌트를 변경하지 않고 기능 추가 가능
- 관심사 분리: UI 로직과 비즈니스 로직을 분리할 수 있음
HOC를 사용하는 이유
1. 중복 코드 제거
다양한 컴포넌트에 반복적으로 들어가는 로직(예: 로그인 체크, API 로딩 상태 처리)을 추상화할 수 있다.
2. 관심사의 분리
UI 로직과 비즈니스 로직을 분리하여 더 유지보수하기 쉬운 코드를 구성할 수 있다.
3. 조합 가능성
HOC는 함수이므로 여러 HOC를 조합 하여 복잡한 로직도 유연하게 처리할 수 있다.
HOC 구현 예제
예시 1: 로그인 여부에 따라 컴포넌트 노출 제어
function withAuth(Component) {
return function AuthComponent(props) {
const isLoggedIn = localStorage.getItem('token');
if (!isLoggedIn) {
return <p>로그인이 필요합니다.</p>;
}
return <Component {...props} />;
};
}
function MyPage() {
return <div>내 정보</div>;
}
export default withAuth(MyPage);
HOC vs Hook vs Render Props
| 개념 | 설명 |
| HOC | 컴포넌트를 감싸서 기능 확장 (컴포넌트를 인자로 받음) |
| Hook | 함수형 컴포넌트 내부에서 로직 재사용 (함수를 호출함) |
| Render Props | 컴포넌트의 children에 함수를 넘겨 실행 (콜백 기반) |
-> HOC는 구조적, Hook은 선언적, Render Props는 함수형 패턴에 가깝다.
React에서의 Memoization 개념과 활용 방법
React 앱의 성능을 최적화하려면 불필요한 연산과 렌더링을 줄이는 것이 핵심이다.
이때 사용하는 고급 최적화 기법이 메모이제이션이다.
Memoization이란?
Memoization은 함수의 연산 결과를 캐시(저장)하여, 같은 입력값이 들어왔을 때 계산을 생략하고 캐시된 값을 재사용하는 기술이다.
React에서의 활용: useMemo, useCallback, React.memo
1. useMemo(): 값 메모이제이션
const expensiveValue = useMemo(() => computeHeavyTask(a, b), [a, b]);
- 특정 연산의 결과를 메모이제이션하여, 의존성이 변경될 때만 재계산한다.
- CPU 사용량이 많은 연산에 사용한다.
2. useCallback(): 함수 메모이제이션
- 주로 자식 컴포넌트에 콜백 함수를 props로 넘길 때 유용하다.
3. React.memo(): 컴포넌트 메모이제이션
const MemoizedComponent = React.memo(MyComponent);
- props가 변경되지 않으면 컴포넌트를 리렌더링하지 않고 이전 결과를 재사용한다.
- Pure Component와 유사한 역할을 하며, 불필요한 렌더링 방지에 효과적이다.
본 후기는 [카카오엔터프라이즈x스나이퍼팩토리] 카카오클라우드로 배우는 AIaaS 마스터 클래스 (B-log) 리뷰로 작성 되었습니다.
'카카오클라우드 AIaaS 교육 > 클라우드 어플리케이션 개발' 카테고리의 다른 글
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY 34 - react (0) | 2025.05.19 |
|---|---|
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY33 - react (0) | 2025.05.13 |
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY32 - js 심화 (2) (0) | 2025.05.13 |
| [스나이퍼팩토리] AIaaS 마스터 클래스 7주차 DAY31 - js 심화 (0) | 2025.05.09 |
| [스나이퍼팩토리] AIaaS 마스터 클래스 6주차 DAY2 - html (2) | 2025.04.30 |