📑 개요
기존에 있던 기능은 아니지만 React 16.8에서부터 생겼다는 React Hooks...!
나는 처음 리액트를 접할 때부터 있던 기능이기 때문에 훅이 없는 리액트...? 상상도 안된다
Hook 없이 어떻게 개발했을까 신기할 정도로 필수인 기능...
포스팅하면서 Hook없이 개발한 코드를 스을쩍 봤는 Hook이 없으면 Vue랑 비슷한 느낌으로 개발하는 것 같다
쓰면서 익숙해지는 게 제일 좋은 개념인데 이게 또 😎.......~!!!!!
냅다 프젝부터 해보면 적응할 건데 이게...~!!!!!!!
넵 공부하겠슴다
🎣 React Hooks란?
React의 클래스 컴포넌트에서만 사용 가능했던 상태(state) 관리 및 생명주기(lifecycle) 관련 기능을 함수형 컴포넌트에서도 사용할 수 있도록 하는 것으로 React 16.8에서 도입되었다.
Hook은 Class 안에서 동작하지 않으며, Class 없이 React를 사용할 수 있게 해주는 것이다.
참고 포스팅
- 사용 규칙
- 최상위에서만 Hook을 호출해야 한다.
반복문, 조건문, 중첩 함수 내에서 실행하면 안 된다. - React 함수 컴포넌트 내에서만 Hook을 호출해야 한다.
일반 JavaScript 함수에서는 Hook을 호출하면 안된다.
함수형 컴포넌트와 직접 작성한 custom Hook에서만 호출해야 한다.
🎏 React Hooks의 주요 기능
- useState()
상태를 관리할 때 사용하는 것으로 상태 값과 해당 값을 갱신하는 함수를 반환한다.
함수는 이벤트 핸들러나 다른 곳에서 호출이 가능하다.
사용법과 예시
- 현재의 state 값과 이 값을 업데이트 하는 함수를 쌍으로 제공한다.
- this.setState와 거의 유사하나, 이전 state와 새로운 state를 합치지 않는다는 차이가 있다.
- this.state와 달리 useState의 State는 객체일 필요가 없다. 이 초기값은 첫 번째 렌더링에만 사용된다.
더불어, 정해진 규칙은 아니지만 보통 [선언변수명, set선언변수명]의 형식으로 사용합니다.
import React, { useState } from 'react';
function Counter() {
// count가 새로운 상태 변수가 선언된 곳이며 setCount가 새롭게 할당받는 값을 입력받는 곳이다.
// useState 안의 값이 0이므로 count는 0으로 선언된 상태이다.
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
// 버튼을 클릭하면 setCount를 통해 count의 값이 +1 씩 된다
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
function ExampleWithManyStates() {
// state는 객체일 필요가 없으며, 숫자, 문자열, 배열, boolean 등 다양한 값의 선언이 가능합니다.
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
// ...
}
- useEffect()
React 컴포넌트 안에서 데이터를 가져오거나 읽고, DOM을 직접 조작하는 작업과 같은 동작을 함수 컴포넌트 내에서 수행하게 해준다.
기존 클래스형 컴포넌트의 componentDidMount 나 componentDidUpdate, componentWillUnmount와 같은 목적으로 제공되는 것으로 이들을 하나의 API로 통합한 것이다.
사용법과 예시
사용법을 들어가기에 앞서, useEffect에는 의존성 배열을 주는가, 안 주는가의 방법이 있습니다.
다양한 사용법에 따라 사용 규칙도 달라지고 렌더링 주기도 달라지기 때문에 각 방법들을 모두 숙지하고 차이점을 인지하고 계셔야 합니다.
1. 의존성 배열 없이 useEffect를 실행하여 페이지가 렌더링 될 때마다 데이터가 불러와진다.
단, 불필요한 작업이 반복되어 성능 저하를 일으킬 수 있다는 문제점이 있습니다.
위의 이유로 제가 자주 사용한 방법은 아니었습니다.
useEffect(() => {
console.log('컴포넌트가 렌더링 될 때마다 실행됩니다.');
});
2. 의존성 배열에 빈 배열을 담아줄 경우 처음 렌더링 시에만 함수가 실행된다.
1번의 방법과 달리 페이지가 렌더링 될 때마다 실행되지 않으므로 불필요한 작업을 방지할 수 있습니다.
그러나 특정한 경우(ex. setInterval)에서 프로퍼티의 값을 변경하면서 []의 값을 빈 배열로 둘 경우, 무한 루프의 문제에 빠지게 되는 문제가 발생할 수 있습니다.
useEffect(() => {
console.log('컴포넌트가 마운트 될 때 한 번만 실행됩니다.');
}, []);
// []가 의존성 배열로, 이 의존성 배열이 변경될 때 다시 실행됩니다.
// 다만, 현재는 의존성 배열이 비어 있으므로 컴포넌트가 마운트 될 때만 실행됩니다.
3. 의존성 배열에 state나 props를 넣을 경우 해당 값이 변할 때마다 함수가 실행된다.
개인적으로 가장 많이 사용했던 방법입니다. 의존성 배열의 값이 변할 때마다 렌더가 되므로 특정 조건에 따른 조작을 할 때 편리합니다.
단, 의존성 배열의 값이 잘못된 경우 원하는 대로 실행되지 않으므로 사용에 각별한 주의가 필요합니다.
useEffect(() => {
console.log(count+'의 값이 변할 때마다 실행됩니다.');
}, [count]);
- Clean-up
useEffect 내부에서 반환된 함수는 해당 효과가 사용되는 컴포넌트가 언마운트 되거나 새로운 효과가 실행되기 직전에 호출됩니다. 이를 통해 이전 효과에서 설정된 작업을 제거하거나 해제할 수 있습니다.
import React, { useEffect } from 'react';
function Example() {
useEffect(() => {
const handleClick = () => {
console.log('Button clicked');
};
document.addEventListener('click', handleClick);
// 정리 함수
return () => {
document.removeEventListener('click', handleClick);
};
}, []);
return <button>Click me</button>;
}
export default Example;
- useContext()
Context를 사용해서 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 수 있습니다.
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function ThemeButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme }}>I am themed button</button>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemeButton />
</ThemeContext.Provider>
);
}
- useReducer()
useState의 대체 함수로 (state, action) => newState의 형태로 reducer를 받고 dispatch 메서드와 짝의 형태로 현재 state를 반환한다.
다수의 하윗값을 포함하는 복잡한 정적 로직을 만드는 경우나 다음 state가 이전 state에 의존적인 경우에 보통 useState보다 useReducer를 선호한다.
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
- useCallback()
성능 최적화를 위해 함수를 메모이제이션할 때 사용합니다.
import React, { useState, useCallback } from 'react';
function Button({ onClick }) {
return <button onClick={onClick}>Click me</button>;
}
function App() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<Button onClick={increment} />
</div>
);
}
- useMemo()
성능 최적화를 위해 값이나 함수를 메모이제이션할 때 사용합니다.
import React, { useMemo } from 'react';
function ExpensiveComponent({ data }) {
// Expensive computation here
return <div>{data}</div>;
}
function App() {
const data = useMemo(() => {
// Some expensive computation
return 'Some data';
}, []);
return <ExpensiveComponent data={data} />;
}
여기서 useCallback과 useMemo의 차이가 뭔지 의아해질 것이라고 생각한다.
이 내용은 추후 포스팅 예정.
간단히 먼저 이야기하면 숫자, 문자열, 객체같은 일반 값을 재사용할 때는 useMemo를,
함수를 재사용할 때는 useCallback을 사용할 것을 추천한다.
- useRef()
DOM 요소에 직접 접근하거나, 함수형 컴포넌트 내에서 변수를 유지할 때 사용합니다.
import React, { useRef, useEffect } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onClick = () => {
inputEl.current.focus();
};
useEffect(() => {
inputEl.current.focus();
}, []);
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={onClick}>Focus the input</button>
</div>
);
}
✨ 마무리
실제로 많이 쓰는 Hook은 정해져 있다고 생각하지만 그 외의 Hook들도 상황에 따라 쓰는 일이 생긴다.
하지만 useState와 useEffect는 정말 너~~~~~~무 많이 쓰게 되니까
이 두 개만큼은 꼭! 제대로 숙지하고 넘어가자.
- 요약
- React Hooks
클래스 컴포넌트에서만 사용 가능했던 상태(state) 관리 및 생명주기(lifecycle) 관련 기능을 함수형 컴포넌트에서도 사용할 수 있도록 하는 것. - React Hooks의 주요 기능
- useState()
- useEffect();
- useContext()
- useReducer()
- useCallback()
- useMemo()
- useRef()
참고 문헌
https://ko.legacy.reactjs.org/docs/hooks-overview.html
https://velog.io/@velopert/react-hooks
https://velog.io/@effypark/useEffect-feat.-clean-up useEffect의 무한 루프를 잘 정리해두셨다!
'개발 > Front' 카테고리의 다른 글
[React] Pure Component와 렌더링 (0) | 2024.03.21 |
---|---|
[React] useEffect와 useLayoutEffect의 차이 (1) | 2024.03.21 |
[React] LifeCycle과 LifeCycle 메서드 (2) | 2024.02.28 |
[React] 클래스형 & 함수형 컴포넌트의 생성과 차이, 장단점 (1) | 2024.02.28 |
[React] React 원리 & 가상 돔(Virtual DOM)의 정의와 작동원리 (1) | 2024.02.28 |