- Hook은 기존 함수형 컴포넌트에서도 클래스형 컴포넌트 기능을 사용할 수 있게 하는 기능을 말한다.
- hook은 컴포넌트에서 데이터를 관리(state)하고 데이터가 변경될 때 상호작용(effect) 하기 위해 사용한다.
👉 함수형 컴포넌트에서 React State와 생명주기 기능을 연동할 수 있도록 만들어 줌
리액트 16.8 하위 버전까지는 state를 사용하려면 클래스 컴포넌트(복잡해 오류가 나기 쉬우며 유지보수가 어렵다.)를 사용해야 했다. 이제는 함수형 컴포넌트에서도 state를 사용할 수 있게 되었다.
👉 Hook의 종류 2가지
클래스형 컴포넌트에서 사용하던 state를 함수형 컴포넌트에서는 'useState'를 이용해 사용할 수 있다.
사용방법
import React ,{ useState } from 'react';
const [<상태 값 저장 변수>, <상태 값 갱신 함수>] = useState(<상태 초깃값>);
사용예시
const Example = () => {
const [title, setTitle] = useState("");
// state를 변경할 값 직접 입력
setTitle("Hello");
// 현재 값을 매개변수로 받는 함수 선언
// return 값이 state에 반영된다.
setTitle((cur) => {
return cur + "world";
});
};
- 함수형 컴포넌트에서 side effects들을 실행하기 위해 'useEffect'를 사용할 수 있다.
- useEffect를 사용하면 모든 렌더링하는 요소마다 원하는 작업을 수행할 수 있어 코드의 중복이 줄어든다.
- 클래스의 생명주기 메소드(componentDidMount 등)를 구현할 필요가 없다.
👀 side effects란?
리액트 컴포넌트 안에서 데이터를 가져오거나 구독하고, DOM을 직접 조작하는 모든 동작을 말한다.
👉 즉, 함수 외부에서 로컬의 상태 값을 변경하는 것을 말한다(이는 다른 컴포넌트에 영향을 줄 수도 있어 렌더링 과정에서는 구현할 수가 없다.).
사용방법
const Example = () => {
useEffect(EffectCallback, Deps)
}
사용예시
[예시1]
import { useEffect, useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
// 'Deps'에 [count]를 넘겨줬다는 것은
// count state의 변경이 일어날 때마다 콜백함수를 실행하라는 뜻
useEffect(() => {
console.log(`${count}번 클릭했다!`);
}, [count]);
return (
<div>
<button onClick={()=>{setCount(count+1)}}>클릭하시오</button>
</div>
)
};
[예시2]
Deps 부분에 아무것도 넘겨주지 않았는데(빈 배열), 컴포넌트 생성시 최초로 한 번은 실행되기 때문에 이는 컴포넌트 생성 또는 소멸시 한 번만 실행해 달라는 뜻이다.
👉 Effect Callback 함수에서 반환하는 함수는 현재 상태가 종료될 때 호출된다.(반환하지 않고 실행만 하는 것은 현재 상태가 생성될 때이다.)
컴포넌트가 사라지기 전에 setInterval을 멈출 필요가 있는데, 이 때 사용하는 것이 'clearInterval'이다. 즉, Deps가 바뀌어 컴포넌트를 재렌더링 하기 전에 이 함수를 실행하면 되는 것이다.
👉 왜냐하면, 해당 컴포넌트를 사용하지 않는 상태에서도 setInterval은 계속 작동하게 되는데 계속 렌더링 해서 부하를 줄 필요가 없기 때문이다.
import { useEffect, useState } from "react";
const Example = () => {
useEffect(() => {
// state가 변경될 때 혹은 컴포넌트를 재렌더링할 때 실행되는 함수
// 생성시 실행되는 함수
const intervalId = setInterval(() => {
console.log("안녕하세요!");
}, 1000);
// 컴포넌트를 재렌더링 하기 전에, 컴포넌트가 없어질 때
// 소멸시 실행되는 함수
return () => {
clearInterval(intervalId);
};
}, []);
};
👉 위의 예시 외에도 백엔드의 데이터(API 불러오기)를 사용해야 할 경우 'useEffect'를 사용할 수 있다.
⚡ 만약 조건부로 side effect를 실행하려면 useEffect를 조건문 안에 넣어서는 안되며 조건문을 useEffect 안에 넣어야 한다.
⚡ 리액트는 hook이 호출되는 순서에 의존하기 때문에 반드시 함수의 최상위에서 hook을 사용해야 한다.
다른 여러가지의 hooks가 있지만 아래의 세 개만 알아본다.👇👇
useMemo, useCallback, useRef
사용 예시
const Example = () => {
const [firstName, setFirstName] = useState('영희')
const [lastName, setLastName] = useState("김");
// 이름과 성이 바뀔 때마다 풀네임을 메모이제이션 한다.
const fullName = useMemo(()=>{
return `${firstName} ${lastName}`
}, [firstName, lastName])
}
const Example = () => {
const [firstName, setFirstName] = useState('영희')
const [lastName, setLastName] = useState("김");
// 이름과 성이 바뀔 때마다 풀네임을 메모이제이션 한다.
const fullName = useCallback(()=>{
return `${firstName} ${lastName}`
}, [firstName, lastName])
return (
<div>
// 함수를 호출해 리턴 값을 반환한다.
{fullName()}
</div>
);
}
const Example = () => {
const inputRef = useRef(null);
const onButtonClick = () => {
// inputRef.current에는 input element object가 할당됨
// focus를 사용하면 input element에 focus하라는 뜻
inputRef.current.focus();
// 아래와 같이 value를 사용하면 input element의 value값을 가져올 수 있음
inputRef.current.value();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={onButtonClick}>
input으로 포커스
</button>
</div>
)
};
- 입력된 이름에 따라 관리자인지 확인하는 상태(예시: const [isAdmin, setBeAdmin] = useState(false)) 같은 것이 추가될 수 있기 때문에 나만의 Hook을 만들어 State Hook과 분리하는 좋다.
- 스케일이 큰 프로젝트를 할 때 state 관리하기에 좋다.
나만의 hook을 통해 로직의 재사용성을 높일 수 있다.
나만의 hook 사용규칙
나만의 hook 예시
const useUser = () => {
const [nickname, setNickname] = useState('')
const updateNickname = event => {
const nickname = event.target.value
setNickname(nickname)
}
// updateNickname 메소드를 함께 반환한다.
return [nickname, updateNickname]
}
// 아래와 같이 User 컴포넌트에서 useUser() 를 호출해서 사용할 수 있다.
// 그러면 아래의 'setNickname'은 'updateNickname'함수가 된다.
const User = () = {
const [nickname, setNickname] = useUser();
...
}
[Toggle 사용 예시]
<./hooks/useToggle.js>
const useToggle = (initialValue) => {
const [isOn, setIsOn] = useState(initialValue);
const toggle = ()=> {
setIsOn((cur) => {
return !cur;
});
}
return [isOn, toggle];
}
<App.js>
function App() {
const [isOn, toggle] = useToggle(false);
...
왜 컴포넌트 내에서 변수를 안쓰고 state를 사용할까?
왜 컴포넌트 내에서 변수를 안쓰고 state를 사용할까?
🐧 이 글은 엘리스 AI 트랙 과정 중 'React 기초' 강의 내용을 바탕으로 작성 되었습니다.