함수 컴포넌트에서는 state나 lifecycle method를 활용할 수 없는데, 이것을 보완해주기 위해 나온 것이 Hooks 이다.
Hook = 갈고리
이미 있는 프로그램에 갈고리를 걸어 끼어들어가 함께 수행되는 것을 의미한다
Hook은 모두 use로 사용되는데, 이것은 클래스 컴포넌트에서 사용되는 기능들에 갈고리를 걸어 "사용"하겠다는 의미를 담았다고 볼 수 있다.
state를 사용하기 위한 hooks 해당 코드에서는 count라는 변수가 증가하고는 있지만, 재랜더링이 일어나지 않아 화면에 표시되지 않고 있다. 따라서 state를 활용하여 값이 바뀔 때마다 재랜더링하여 값을 표시해줘야하는데, 함수 컴포넌트이기 때문에 state 기능이 지원되지 않는다.
const [변수명, set함수명] = useState(초기값);
변수 각각에 대해 set함수가 따로 존재한다.
side effect(효과,영향 ex데이터를 받아오거나, 수동적으로 dom을 변경)를 수행하기 위한 hooks
이러한 effect들은 다른 컴포넌트에 영향을 끼칠 수 있으며, 렌더링 시에는 작업이 완료될 수 없고, 렌더링이 끝난 후에 진행된다.
useEffect(이펙트 함수, 의존성 배열);
의존성 배열 안의 값이 하나라도 변경되었을 때 이펙트 함수를 실행한다.
useEffect(이펙트 함수, []);
props나 state에 의존하지 않으므로 여러번 실행되지 않는다.
useEffect(이펙트 함수);
useState과 useEffect 모두 하나의 컴포넌트 안에서 여러번 사용될 수 있으며, useEffect의 return문은 unmount 시에 실행되는 것과 똑같은 역할을 한다.
memoized value를 리턴하는 hook
memoization : 비용이 높은 함수의 호출 결과를 저장해두었다가, 같은 값으로 함수를 호출하면 이전에 저장해두었던 결과를 출력하는 것. 컴퓨터의 자원을 적게 쓸 수 있다. memoization이 적용된 값을 memoized value라고 한다.따라서 빠른 렌더링 효과를 얻을 수 있는 장점이 있다.
useMemo를 적용한 함수는 렌더링이 일어날 때 실행된다.
useMemo()와 비슷한 역할을 하지만, 값이 아니라 함수를 반환한다. 의존성 배열의 값이 바뀔 때만 함수를 새로 정의해 리턴해준다.
리액트에서 reference : 특정 컴포넌트에 접근할 수 있는 객체
refObject.current : 현재 참조하고 있는 Element
변경 가능한 current라는 속성을 가진 하나의 상자라고 생각하면 쉽다.버튼 클릭 시 input에 focus하게 하는 코드
useRef hook은 내부의 데이터가 변경되었을 때 알리지 않는다. 따라서 useCallback을 사용하여 Callbackref hook을 이용하기도 한다.
1️⃣ hook은 무조건 최상위 레벨에서만 호출해야한다 (*if문이나 다른 조건문 안에서 사용될 수 없음)
2️⃣ react 함수 컴포넌트에서만 hook을 호출해야한다
eslint-plugin-react-hooks package를 사용하면 hook의 규칙에 맞게 경고를 띄워주는 등 도움을 받을 수 있다.
https://www.npmjs.com/package/eslint-plugin-react-hooks
동일한 hook이 여러번 작성되어 코드의 간결성이 떨어지는 문제를 해결하기 위해 이름이 use로 시작하고, 내부에서 다른 hook을 호출하는 하나의 자바스크립트 함수 custom hook을 사용할 수 있다. 위와 같이 사용자의 온/오프라인 state에 따라 텍스트의 색상을 다르게 하는 기능을 custom hook을 통해 간결하게 분리할 수 있으며, 재사용성도 높아진다.
useCounter라는 custom hook을 만들어 증가와 감소를 정의해준다.
import React, { useState } from "react";
function useCounter(initialValue) {
const [count, setCount] = useState(initialValue);
const increaseCount = () => setCount((count => count + 1));
const decreaseCount = () => setCount((count) => Math.max(count -1 , 0));
return [count, increaseCount, decreaseCount];
}
export default useCounter
accomodation.jsx에서
import React, { useState, useEffect } from 'react';
import useCounter from './useCounter';
const MAX_CAPACITY = 10;
function Accommocate() {
const [isFull, setIsFull] = useState(false);
const [count, increaseCount, decreaseCount] = useCounter(0);
useEffect(() => {
console.log("======================");
console.log("useEffect() is called.");
console.log(`isFull: ${isFull}`);
});
useEffect(() => {
setIsFull(count >= MAX_CAPACITY);
console.log(`Current count value: ${count}`);
}, [count]);
return (
<div style={{padding: 16}}>
<p>{`총 ${count}명 수용했습니다.`}</p>
<button onClick={increaseCount} disabled={isFull}>
입장
</button>
<button onClick={decreaseCount}>퇴장</button>
{isFull && <p style={{color: "red"}}>정원이 가득찼습니다.</p>}
</div>
);
}
export default Accommocate
의존성 배열이 없는 useEffect는 컴포넌트 상태가 업데이트 될 때마다 호출되고, 의존성 배열에 count가 있는 useEffect는 count의 값이 변경될 때마다 호출된다.
결과
참고