React 16.8버전부터 새롭게 추가된 Hook은 기존 class를 사용하지 않고, React state와 lifecycle features를 연동할 수 있게 해주는 함수다.
기존 class를 사용한 React는 코드의 재사용성이 낮고, 작성하기 까다로우며, reloading이 신뢰하기 어렵다.
이러한 class가 가진 문제들을 함수형 컴포넌트 기능을 사용해 해결할 수 있는데, 함수형 컴포넌트는 state나 lifecycle을 직접 다룰 수 없다.
Hook은 함수형 컴포넌트가 class 컴포넌트의 역할을 할 수 있게 해준다.
import React, { useState } frome 'react';
const [value, setValue] = useState(initialValue);
useState()
는 함수형 컴포넌트에서도 가변적인 state를 지닐 수 있게 하는 Hook이다. useState()
는 길이가 2인 배열을 반환하는데, 첫번째는 상태 값, 두 번째는 상태를 업데이트하는 함수이다.
initalValue는 초깃값으로 최초 렌더링 시에 한 번 사용된다. 해당 함수에 파라미터를 넣어 호출하면, 전달받은 바라미터 값이 바뀌고 컴포넌트는 정상적으로 리렌더링된다.
아래는 useState()
를 사용해 만든 카운트업 예제
import React, { useState } from 'react';
export default function App() {
const [count, setCount] = useState(0);
return (
<div>
{`count: ${count}`}
<button onClick={() => setCount(prev => prev + 1)}>+</button>
</div>
)
}
import React, { useRef } from 'react';
const valueRef = useRef(initalValue);
자바스크립트의 querySelector()
또는 getElememtById()
같이 DOM을 선택할때 사용하는 Hook이다.
React 컴포넌트에서 state는 상태를 바꾸는 함수를 호출한 이후 업데이트 된 상태를 조회할 수 있으나, useRef()
를 사용할 경우 바로 조회가 가능하다.
아래는 useState()
와 useRef()
로 input에 입력한 value를 리셋하고 input 창을 포커싱하는 예제.
import React, { useState, useRef } from 'react'
export default function Practice09() {
const input = useRef(null);
const [text, setText] = useState("");
const handleClick = () => {
setText("");
input.current.focus();
}
return (
<div>
<span>현재 value는 { text }입니다.</span><br />
<input type="text" ref={ input } value={ text } onChange={(e) => setText(e.target.value)} />
<button onClick={handleClick}>RESET</button>
</div>
)
}
import React, { useEffect } from 'react';
useEffect(() => {}, []);
컴포넌트가 렌더링 될 때마다 특정 작업을 실행하게 하는 Hook.
useEffect()
의 매개변수는 익명함수와 빈배열 두 가지 요소를 가진다. 배열은 빈 배열일때 처음 렌더링에만 실행되며, 값이 있으면 특정 상태 값이 업데이트 될 때만 실행된다. 마지막으로, 아예 배열이 생략된다면 리렌더링 될때마다 실행된다.
컴포넌트가 언마운트 되기전 또는 업데이트 직전 어떤 작업을 수행하고 싶다면, clean-up 함수를 반환해야한다.
clean-up 함수는 컴포넌트가 마운트 되기 전과 업데이트 전에 실행되며, 업데이트 전에 실행될 경우 업데이트 직전 state 값에 접근이 가능하다.
아래는 useState()
와 useEffect()
를 사용해 input 값이 3초 뒤 나오게 하는 예제로, useEffect()
에 clean-up 함수를 넣어 value 값이 마지막 값으로만 나오게 설정했다.
import React, { useState, useEffect } from 'react'
export default function App() {
const [value, setValue] = useState('');
const [num, setNum] = useState("값을 입력하세요.");
const [res, setRes] = useState("");
useEffect(() => {
if (value === "") {
return setNum("값을 입력하세요.")
} else {
const a = setTimeout(() => setNum("3초 뒤 실행됩니다."), 0);
const b = setTimeout(() => setNum("2초 뒤 실행됩니다."), 1000);
const c = setTimeout(() => setNum("1초 뒤 실행됩니다."), 2000);
const d = setTimeout(() => setNum("실행 완료"), 3000);
const e = setTimeout(() => setRes(value), 3000);
return () => {
clearTimeout(a);
clearTimeout(b);
clearTimeout(c);
clearTimeout(d);
clearTimeout(e);
}
}
}, [value]);
return (
<>
<input
type="number"
onChange={(e) => {setValue(e.target.value)}}
/>
<br />
{ num }
<br/>
{`예상 값: ${ value }`}
<br />
{`출력 값: ${ res }`}
</>
)
}
import React, { useMemo } from 'react';
const memoizationValue = useMemo(() => 함수, 배열);
React에서 컴포넌트의 렌더링은 계속해서 일어나고 있다. 간단한 구조라면 무리없이 재렌더링이 가능할 것이다. 그러나 복잡한 수식을 계산하는 등 리턴 값이 수초 이상 걸리는 구조라면 재렌더링할때마다 해당 수식이 다시 계산되는 일이 발생하며 UI에 지속적으로 지연이 발생된다.
이같은 상황은 memoization 기법을 활용하면 해결할 수 있다.
memoization은 기존에 수행한 연산의 결과값을 어딘가에 저장해두고 동일한 입력이 들어오면 재활용하는 프로그래밍 기법을 말한다. 중복 연산을 피할 수 있기 때문에 성능을 최적화할 수 있다는 장점이 있다.
useMemo()
는 두 개의 인자를 받는다. 첫 번째는 결과값을 생성해주는 팩토리 함수이며, 두 번재는 기존 결과값을 재활용하는 입력값 배열이다.
import React, { useCallback } from 'react';
const callBackValue = useCallback(() => 함수, 배열)
useCallback()
은 함수를 memoization된 값을 반환하여 계속해서 동일한 값을 보내주는 역할을 한다.
useCallback()
은 두 개의 인자를 가지며, 첫 번째는 인라인 콜백, 두 번째는 의존성 값의 배열을 받게 된다. 배열에 변경을 감지해야할 값을 넣어주면, 등록한 함수가 변경될 때마다 새로운 콜백함수를 생성하게 된다.
이것은 최적화된 자식 컴포넌트에 props로 콜백 함수를 내려줄 때 유용하다.
useMemo()
는 memoization된 값을 반환하여 동일 계산 반복수행을 최소화시켜주는 반면, useCallback()
은 memoization된 콜백을 반환하여 새로운 함수가 생성되는 것을 줄이는 역할을 한다는 차이점이 있다.
끝.