useEffect 훅은 컴포넌트 생명 주기에 따른 코드를 작성하고 싶을 때 사용할 수 있는 훅입니다. 아래와 같은 기본 문법 형식을 가집니다.
useEffect(콜백, 의존성 배열); // dependencies array
useEffect(() => {}, []);
컴포넌트 생명주기란, 컴포넌트가 생성되고 삭제가 되는 순간까지 거쳐가는 일련의 주기를 말합니다. 리액트에서는 컴포넌트 생명주기를 ‘생성’, ‘수정(업데이트)’, ‘삭제’의 세 가지로 구분하고 있다.
컴포넌트가 생성되는 시점은 특정 컴포넌트가 웹 브라우저에 렌더링 되는 순간이다.
컴포넌트가 삭제되는 시점은 특정 컴포넌트가 웹 브라우저에서 사라지는 순간이다.
컴포넌트가 수정되는 시점은 컴포넌트에서 관리하고 있는 상태 관리 변수의 값이 변경되었을 때 이다.
컴포넌트 생명주기의 각 시점은 useEffect() 훅으로 체크할 수 있다.
import { useEffect } from "react";
export default function App() {
useEffect(() => {
console.log("Component Created");
}, []);
return <h1 className="text-3xl font-bold underline">Hello world!</h1>;
}
import { useEffect, useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Component Count Updated!" + count);
}, [count]);
return (
<>
<h1>{count}</h1>
<button onClick={() => setCount((count) => count + 1)}>클릭</button>
</>
);
}
간단하게 설명하자면,
useEffect 훅은 두 번째 인자로 전달된 배열의 값이 변경될 때만 실행된다.
--> 이 경우에는 [count] 배열이 전달되었으므로 count 상태가 변경될 때마다 useEffect 내부의 함수가 호출된다.
따라서 사용자가 버튼을 클릭하여 count를 증가시키면 setCount가 호출되고, 이로 인해 count가 변경되면서 useEffect가 실행되어 "Component Count Updated" 메시지가 콘솔에 출력되게 된다.
✚ useEffect 훅 내에서 정의한 정리(cleanup) 함수는 다음 두 가지 경우에 실행된다 :
따라서 return 문으로 정의한 함수는 컴포넌트가 종료될 때 또는 의존성이 변경되기 전에 실행되게 된다.
App.tsx
import { useState } from "react";
import Interval from "./components/Interval";
export default function App() {
const [display, setDisplay] = useState(false);
return (
<>
{display && <Interval />}
<button onClick={() => setDisplay((display) => !display)}>클릭</button>
</>
);
}
import React, { useEffect, useLayoutEffect, useState } from 'react';
export default function App() {
const [count, setCount] = useState(0);
// useEffect(() => {
// if (count === 10) {
// setTimeout(() => {
// setCount(0);
// }, 2000);
// }
// }, [count]);
useLayoutEffect(() => {
if (count === 10) {
setTimeout(() => {
setCount(0);
}, 2000);
}
}, [count]);
return (
<>
<div className="flex flex-col justify-start items-start">
<h1>{count}</h1>
<button onClick={() => setCount((prev) => prev + 1)}>버튼</button>
<button onClick={() => setCount(10)}>10으로 이동 버튼</button>
</div>
</>
);
}
리액트에서 고차 컴포넌트(Higher-Order Component, HOC)는 컴포넌트를 인자로 받아서 새로운 컴포넌트를 반환하는 함수입니다. 고차 컴포넌트는 주로 컴포넌트의 재사용성과 코드의 모듈화를 높이기 위해 사용된다.
React.memo는 React에서 제공하는 고차 컴포넌트(Higher-Order Component)로, 함수형 컴포넌트를 메모이제이션(memoization)하여 성능을 최적화하는 데 사용된다.
기본적으로 React.memo는 주어진 컴포넌트가 동일한 props로 렌더링될 때, 이전에 렌더링된 결과를 재사용하게 함으로써 불필요한 렌더링을 방지하도록 되어져 있다.
import React, { useState } from 'react';
const Counter = React.memo(({ count }) => {
console.log('Counter 렌더링');
return <h1>{count}</h1>;
});
const App = () => {
const [count, setCount] = useState(0);
const [otherState, setOtherState] = useState(false);
return (
<div>
<Counter count={count} />
<button onClick={() => setCount(count + 1)}>Count Up</button>
<button onClick={() => setOtherState(!otherState)}>Toggle Other State</button>
</div>
);
};
export default App;
Counter 컴포넌트는 count가 변경될 때만 렌더링된다. --> otherState가 변경되더라도 Counter는 렌더링되지 않는다.
useCallback 훅은 함수형 컴포넌트에서 함수를 메모이제이션 하는 데 사용된다.
여기서 메모이제이션이란, 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장하여 사용함으로써 동일한 계산의 반복 수행을 제거하여 성능 향상을 도모하는 기술을 말한다.
const cachedFn = useCallback(fn, dependencies)
import React, { useState } from 'react';
const functionSet = new Set();
const App = () => {
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
const decrement = () => {
setCount(count - 1);
};
const increment = () => {
setCount(count + 1);
};
const otherIncrement = () => {
setCount2(count2 + 1);
};
functionSet.add(decrement);
functionSet.add(increment);
functionSet.add(otherIncrement);
console.log(functionSet);
return (
<div>
<h1>Count:{count}</h1>
<button onClick={decrement}>-</button>
<button onClick={increment}>+</button>
<hr />
<h1>Count2:{count2}</h1>
<button onClick={otherIncrement}>+</button>
</div>
);
};
export default App;
메모이제이션: decrement, increment, otherIncrement 함수에 useCallback을 적용하여 이 함수들이 의존성 배열이 변경되지 않는 한 동일한 참조를 유지하도록 하였다.
성능 최적화: useCallback을 사용함으로써 컴포넌트가 리렌더링될 때마다 이 함수들이 새로 생성되지 않으므로, functionSet의 내용이 변하지 않고 메모리 사용이 최적화 된다.
useMemo 훅은 값을 메모이제이션 하는 훅이다.
여기서 메모이제이션이란, 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장하여 사용함으로써 동일한 계산의 반복 수행을 제거하여 성능 향상을 도모하는 기술을 말한다.
import React, { useState, useMemo } from 'react';
const App = () => {
const [count, setCount] = useState(0);
const [otherCount, setOtherCount] = useState(0);
// count의 제곱을 계산하는 함수
const squaredCount = useMemo(() => {
console.log('Count의 제곱을 계산 중...');
return count * count;
}, [count]); // count가 변경될 때만 재계산
return (
<div>
<h1>Count: {count}</h1>
<h2>Count의 제곱: {squaredCount}</h2>
<button onClick={() => setCount(count + 1)}>Count 증가</button>
<hr />
<h1>Other Count: {otherCount}</h1>
<button onClick={() => setOtherCount(otherCount + 1)}>Other Count 증가</button>
</div>
);
};
export default App;
squaredCount는 useMemo를 사용하여 count의 제곱 값을 메모이제이션 한다.
의존성 배열에 count를 넣어, count가 변경될 때만 계산이 이루어지도록 한다.
이때, count가 변경되지 않는 한 이전의 계산 결과를 재사용하므로 성능이 향상된다.
렌더링:
버튼 클릭 시 count를 증가시키면, squaredCount의 값이 새롭게 계산된다.
otherCount 버튼을 클릭해도 squaredCount는 재계산되지 않는다.
조금 더 복잡한 상태 관리를 할 때 사용하는 리액트 훅이다. 넓은 범위에서 useState 훅과 비슷하다.
const [state, dispatch] = useReducer(reducer, initialState)
import { useReducer } from "react";
import "./Counter.css";
const reducer = (state: number, action: { type: string }) => {
switch (action.type) {
case "increament":
return state + 1;
case "decreament":
return state - 1;
default:
return state;
}
};
const Counter = () => {
const [counter, dispatch] = useReducer(reducer, 0);
return (
<div className="counter">
<h1>{counter}</h1>
<div>
<button onClick={() => dispatch({ type: "decreament" })}>-</button>
<button onClick={() => dispatch({ type: "increament" })}>+</button>
</div>
</div>
);
};
export default Counter;
리액트의
useContext는 리액트 훅 중 하나로, 컨텍스트(Context)를 쉽게 사용하게 해주는 훅입니다.useContext를 사용하면 컨텍스트 API를 통해 전역적으로 상태를 관리하거나, 컴포넌트 트리에서 prop drilling을 피할 수 있습니다.
Context는 주로 애플리케이션에서 전역적으로 사용할 수 있는 데이터를 제공하는 데 사용된다.
예: 사용자 인증 상태, 테마 설정, 언어 선택 등.
Context는 React.createContext()를 사용하여 생성하고, Provider를 통해 데이터를 제공하며, useContext 훅을 통해 데이터를 소비할 수 있다.
import React, { createContext, useContext, useState } from 'react';
// 1. Context 생성
const ThemeContext = createContext();
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
위에서 정의한 것을 useContext 훅을 사용해서 ThemeContext를 소비할 수 있다.
const ThemeSwitcher = () => {
// 3. useContext로 컨텍스트 값 사용
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div>
<p>현재 테마: {theme}</p>
<button onClick={toggleTheme}>테마 변경</button>
</div>
);
};
마지막을 ThemeProvider로 컴포넌트 트리를 감싸서 모든 하위 컴포넌트가 ThemeContext에 접근이 가능하도록 한다
const App = () => {
return (
<ThemeProvider>
<ThemeSwitcher />
</ThemeProvider>
);
};
export default App;
본 후기는 본 후기는 [유데미x스나이퍼팩토리] 프로젝트 캠프 : Next.js 3기 과정(B-log) 리뷰로 작성 되었습니다.
#유데미 #udemy #웅진씽크빅 #스나이퍼팩토리 #인사이드아웃 #미래내일일경험 #프로젝트캠프 #부트캠프 #React #리액트프로젝트 #프론트엔드개발자양성과정 #개발자교육과정