리액트 훅스는 리액트 버전 16.8에서 소개된 기능인데, 등장 배경은 기존의 클래서 기반 컴포넌트를 사용하는 방식에 대한 개선이 주된 목적이라고 한다.
기존에는 state와 생명주기 메소드들을 가지는 클래스 기반 컴포넌트를 사용하였으나,
클래스 기반 컴포넌트의 경우에,
1. 코드의 복잡성이 증가하고
2. 버그의 유발 가능성이 높아져서 새로운 방식의 개선이 필요했던 것이다.
리액트 훅스는 함수기반 컴포넌트를 통해 state와 생명주기 메소드들을 사용할 수 있게 해주며,
함수 기반 컴포넌트의 경우
1. 코드의 간결성이 높아져 직관적인 코드작성이 가능하고
2. 버그의 발생 가능성이 낮아져서 개발자들의 편의성을 높여준다.
클래스 기반 컴포넌트와 함수형 컴포넌트가 뭐가 다른데?
클래스 기반 컴포넌트는 뭐가 더 좋은데?
1. 더 나은 코드 구조
클래스 컴포넌트를 사용하면, 리액트 어플리케이션에서 복잡한 로직을 모아 분류할 수 있어서 코드구조를 깔끔하게 유지할 수 있다.
2. 더 강력한 라이프 사이클 메소드
클래스 컴포넌트에서는 라이프 사이클 메소드를 사용할 수 있어, 컴포넌트가 렌더링되는 과정에서 특정 액션을 수행하거나데이터를 관리할 수 있다.
3. 고급 컴포넌트 상속
클래스 기반 컴포넌트는 고급 컴포넌트 상속을 통해 다른 컴포넌트에서 재사용가능한 코드를 작성할 수 있다.
그럼 거꾸로 보자.
함수 기반 컴포넌트가 클래스 기반 컴포넌트보다 왜 좋은데?
1. 코드의 간결성
함수 기반 컴포넌트는 클래스 기반 컴포넌트에 비해 더 간결한 코드를 작성할 수 있다.
2. 쉬운 테스트
함수 기반 컴포넌트는 단순한 함수이기 때문에 더 쉽게 테스트할 수 있다
3. 편리한 상태 관리
함수 기반 컴포넌트에서는 Hooks을 사용하여 상태 관리가 더 편리하게 이루어진다.
4. 재사용성
함수 기반 컴포넌트는 단순한 함수이기 때문에 더 쉽게 재사용할 수 있다.
훅스를 사용할때 규칙이 몇가지 있다. 숙지하지 않으면 에러를 마주하게 된다.
1. 훅스는 항상 루트 컴포넌트의 최상위에서만 사용해야한다.
2. 훅스는 함수 호출시점에서 매번 동일한 결과를 반환해야한다
3. 훅스는 컴포넌트 내부에서만 사용해야한다.
- 커스텀 훅스나 컴포넌트 밖에서 사용할 수 없다.
4. 훅스 사용 순서가 같아야한다.
- 예를 들어서 useState 뒤에 useEffect를 써야한다.
훅스는 다음과 같은 것들이 있다.
기본 Hooks
- useState
- useEffect
- useContext
추가 Hooks
- useReducer
- useCallback
- useMemo
- useRef
- useImperativeHandle
- useLayoutEffect
- useDebugValue
1. useState
state관리를 위한 훅으로서
기존 클래스 기반 컴포넌트에서는 this.setState()가 이 기능을 수행했다.
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
2. useEffect
사이드 이펙트를 처리하는 훅이다.
componentDidMount
componentDidUpdate
componentWillUnmount와 같은 메소드의 기능을 수행한다.
난 개인적으로 useEffect가 제일 잘 알아야하는 훅이 아닌가 생각한다.
useEffect의 실행 타이밍은 다음과 같다!
1. 컴포넌트가 렌더링된다.
2. 화면이 업데이트된다
3. useEffect가 실행된다
그럼 화면이 업데이트되기 전에 useEffect를 수행하고 싶으면
useLayoutEffect를 사용하면
1. 컴포넌트가 렌더링되고
2. useLayoutEffect
3. 화면이 업데이트 된다
useEffect( ()=>{
// componentDidMount
// componentDidUpdate
// 의존성 배열을 어떻게 사용하느냐에 따라서 정해진다.
return () =>{
// componentWillUnmount
// 보통 클린업 함수를 여기서 사용한다
}
,[]}
3. useContext
context API를 편리하게 사용하기 위한 훅이다.
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function Example() {
const theme = useContext(ThemeContext);
return <div>Current theme is {theme}</div>;
}
4. useReducer
state관리와 관련된 로직을 캡슐화하여 사용하기 위한 훅
import React, { useReducer } from 'react';
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 Example() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
5. useCallback
useCallback은 함수컴포넌트에서 렌더링 성능을 최적화하는데에 사용된다.
기존의 클래스 기반 컴포넌트에서는 shouldComponentUpdate 메소드를 사용해서 렌더링을 최적화했지만, 함수기반 컴포넌트에서는 useCallback을 사용해서 렌더링을 최적화할 수 있다.
난 최적화가 [ 굳이 하지 말아도 될 짓 안하게 만드는 것 ]이라고 생각한다.
useCallback은 두개의 인수를 가진다.
1. 새로운 함수를 만드는 함수
2. 의존성 배열
의존성 배열은 함수가 사용하는 변수나 객체 등을 포함한다.
import React, { useCallback } from 'react';
const MyComponent = ({ data }) => {
const handleClick = useCallback(() => {
console.log(data);
}, [data]);
return <button onClick={handleClick}>Click me</button>;
};
여기서 useCallback을 사용해서 handleClick 함수를 만들었다.
함수형에서는 다시 함수가 호출될때 내부 요소들이 다시 선언되고 메모리를 사용하기 마련인데
useCallback을 사용하면 이경우에는 data값이 이전과 다르지 않다면, handleClick 함수를 다시 생성하지 않고 기존의 함수를 재사용한다.
그니까 쓸데없는 재생성을 하는 것을 막는다는 것이다.
6. useMemo
useMemo는 어찌보면 useCallback과 비슷하다.
useMemo는 함수형 컴포넌트에서 특정 값을 계산하고 캐시하는데에 사용된다
useMemo는 값을 계산하고 캐시할 때 성능 최적화를 수행할 수 있는 장점이 있다.
일반적으로, 복잡한 연산을 수행하거나 state에서 여러번 참조하는 값을 계산할 때 사용된다
import React, { useMemo } from 'react';
function MyComponent({ data }) {
const processedData = useMemo(() => doExpensiveCalculation(data), [data]);
return <div>{processedData}</div>;
}
function doExpensiveCalculation(data) {
// Perform complex calculation on data
return processedData;
}
여기서 보면, useMemo는 data 값이 변경될 때만 doExpensiveCalculation 함수를 실행하고, 그 외의 경우에는 캐시된 결과 값을 반환한다. 이것은 불필요한 계산을 방지해서 어플리케이션의 성능을 향상시키는 효과가 있다.
첫번째 인자는 컴포넌트가 렌더링될 때, 계산하는 값을 정의한다.
두번째 인자인 의존성 배열은 값을 기억할때 사용할 변수 혹은 함수들의 목록을 정의한다
만약에 의존성 배열에 정의된 값이 변경될 때, 그 값을 기억하는 것은 무시되고, 함수가 다시 호출되어 새로운 값이 기억된다.
그렇다면, 무조건 모든 함수에 useMemo를 하는게 맞냐고 생각할 수 있다.
음 그럴듯한 이야기긴한데, useMemo도 비용이 없는 훅은 아니기 때문에 ( 비교를 수행하지 않나 ) 고민을 하고 사용해야한다. 무거운 계산이 아니라면 useMemo의 효과가 미미하거나 거의 없을 수도 있다.
'리액트 네이티브' 카테고리의 다른 글
일반적 함수 선언과 화살표 함수선언 뭐가 다르지? (0) | 2023.02.14 |
---|---|
FlatList 컴포넌트에 대해서 깊게 알아보자 (0) | 2023.02.14 |
코드작성규칙(최신화 02-10) (0) | 2023.02.10 |
내가 짠 코드가 정말 최선일까 (0) | 2023.02.09 |
API 명세를 작성해야한다! (4) | 2023.02.08 |
댓글