React Hook에 대해서!
❓훅(Hook)
- 클래스 형식의 리액트 컴포넌트에서만 할 수 있었던 state관리나 라이프사이클등을 함수 형태컴포넌트에서도 사용할 수 있게 만들어주는 기능
사용규칙!!
- 훅은 최상위 레벨에서만 호출 가능. 즉, 반복문, 조건문, 중첩된 함수 내부에서 호출하면 안됨.
- 훅은 오직 리액트 함수 컴포넌트 내에서만 호출 가능
⇒ 그래서 왜씀?
- 코드가 간결해져 가독성이 좋아진다.
- 많은 라이브러리들도 훅으로만 나오고 있다.
- HOC 헬을 벗어 날 수 있다.
- 불필요한 것 같은 코드를 적을 필요가 없다.
📌useEffect
- 클래스 형식의 리액트 컴포넌트에서만 할 수 있었던 state관리나 라이프사이클등을 함수 형태 컴포넌트에서도 사용할 수 있게 만들어주는 기능
- SideEffect 를 발생하는 작업을 수행하는 훅 API
*side effect : A라는 작업을 진행했을때 A 만 영향이 가는게 아니라 B에도 영향이 갈 수 있는 것을 SideEffect 라고 일컫는다.
useEffect - 마운트시
useEffect(() => {
console.log('useEffect');
}, []);
- 두 번째 인자에 빈 배열을 넣는 경우, 마운트 될 때에 콜백 함수 내부를 실행하고 언마운트 될 때에 cleanup 함수를 실행합니다.
- componentDidMount 의 역할로써 사용하려면 [] 빈배열을 dependency (deps 라고 부르기도함) 에 넣어주면 된다.
useEffect - 업데이트시
useEffect(() => {
console.log('useEffect');
}, [state]);
- 특정 값이 업데이트 되었을 때만 실행하고 싶은 경우에는 두 번째 인자에 특정 값을 담은
배열을 넣어주면 됩니다.
- 또한, 배열에는 여러 개의 값을 넣을 수 있고 일반적으로는 콜백 함수 내에 사용된 state
변수를 배열에 담는 편이지만 편의에 따라 해당 값을 안 넣을 수도 있고, 콜백 함수 내부에서 사용하지 않는 값을 넣을 수 있습니다.
- 이때, 리액트 측에서 setState 함수는 동일성을 보장하고 변경되지 않는다고 하므로
넣어줄 필요가 없습니다.
useEffect - 언마운트시
useEffect(() => {
console.log('useEffect');
return ()=>{
console.log(‘뒷정리하기’);
};
}, []);
- useEffect는 기본적으로 렌더링되고 난 직후마다 실행되고, 두번째 파라미터
배열에 무엇을 넣는지에 따라 실행되는 조건이 달라집니다.
- 컴포넌트가 언마운트되기 전이나 업데이트되기 직전에 어떠한 작업을 수행하고
싶다면 useEffect에서 return을 통해서 뒷정리(cleanup)함수를 반환해줍니다.
- 오직 언마운트될때만 뒷정리함수를 호출하고 싶다면, useEffect함수의 두번째
파라미터에 비어있는 배열만 넣어주면 됩니다.
📌useRef
useRef의 Ref는 reference의 약자로, 저장공간(변수 관리), DOM 요소에 접근을 위해
사용되는 리액트 훅
import React, { useState, useEffect } from 'react';
const Clock = () => {
const [time, setTime] = useState(new Date());
useEffect(() => {
const timer = setTimeout(() => {
console.log(‘setTimeout’);
setTime(new Date());
}, 1000);
return () => {
console.log(clearTimeout’);
clearTimeout(timer);
};
}, [time]);
return (
<div>
<h2>{time.toLocaleString()}</h2>
</div>
)
}
- useEffect 의 dependency 에 ‘time’ 이라는 state 변수를 둠으로써 time 값이 바뀔때마다 화면이 리렌더링 될 수 있도록 한다. 메모리 누수가 발생하지 않도록 useEffect 의 로직이 종료될 때 clearTimeout() 함수를 return 하도록 한다.
useRef - 저장공간
- 저장공간하면 state => useState 사용
- 리액트 컴포넌트는 state값이 변할 때마다 다시 렌더링이 되면서 컴포넌트 내부
변수들이 초기화가 됩니다.
컴포넌트 내부 변수들이 초기화된다는 것은 해당 컴포넌트 함수의 변수들이 모두
초기화가 되고 함수 로직 등이 다시 실행된다는 의미입니다.
이로써 원하지 않는 부분까지 리렌더링이 일어나는 문제가 있습니다.
- 이런경우, state대신 ref를 사용하여 불필요한 렌더링을 막을 수 있습니다.
- state변화 => 렌더링 => 컴포넌트 내부 변수들 초기화
ref 변화 => 렌더링이 일어나지 않음 => 변수들의 값 유지
- state의 변화 => 렌더링 => ref의 값은 유지됨
즉 변한 값은 저장하되, 값이 변경되었다고 렌더링되는 것 까지 원하지 않을때 사용
useRef - DOM
- 로그인 페이지에 들어갔을때 바로 아이디를 입력할 수 있도록 input에 포커스를 어떻게 주면 될까요?
const inputRef = useRef();
useEffect(() => {
console.log(inputRef);
inputRef.current.focus();
}, [])
const loginAlert = () => {
alert(`환영합니다. ${inputRef.current.value}`);
inputRef.current.focus();
}
return (
<div className="App">
<header className="App-header">
<input ref={inputRef} type="text" placeholder="id"/>
<button onClick={loginAlert}>Login</button>
</header>
</div>
);
📌useMemo
- useMemo와 useCallback은 리렌더링을 최적하는 데 도움이 되도록 만들어졌습니다.
리렌더링을 최적화하기 위해서는 아래의 두가지 방법이 있습니다.
- 주어진 렌더에서 수행해야하는 작업의 양을 줄이기
- 컴포넌트의 리렌더링 횟수를 줄이기
const memoizedValue = useMemo(callback, dependency);
- 연산 최적화에 사용하는 API로 렌더링 과정에서 두 번째 인자로 받은 의존 배열(dependency)내 값이 바뀌는 경우에만 첫 번째 인자로 받은 콜백 함수를 실행하여 구한 값을 반환하는 함수
- useMemo 훅을 사용해서 렌더링하는 과정에서 특정값이 바뀌었을 때만 연산을 실행하고, 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용하는 방식으로 구현해줍니다.
- Memoization(메모이제이션) 알고리즘은 주어진 입력값에 대한 결과를 저장함으로써 같은 입력값에 대해 함수가 한 번만 실행되는 것을 보장 => useMemo라고 명칭이 된 이유
📌useCallback
const memoizedCallback = useCallback(callback, dependency);
- 렌더링 최적화에 사용하는 훅 API로 렌더링 과정에서 두 번째 인자로 주어진 의존 배열(dependency)의값이 바뀌면 첫 번째 인자로 주어진 콜백함수(callback)를 새로 생성하여 반환합니다.
- 참고로, 의존 배열에 따른 작동 방식은 useEffect()와 같이 배열을 넣지 않은 경우에는
- 매 렌더링마다, 마운트 때에만 실행이 되고
- 특정 값을 넣는 경우에는 특정 값이 변하여 렌더링 될 때에만 해당 훅 API가 실행됩니다.
const onClick = useCallback(e => {
e.preventDefault();
setNumber(number + 1);
), [number]};
이 함수는 number의 값이 변할 때마다 number의 값에 1을 더해주는 함수를 기억하고 있다가 클릭이벤트가 발생할 경우 해당 함수를 실행시킵니다.
useMemo는 메모이제이션된 값을 반환해서 함수를 실행하는데, useCallback은 함수를 반환합니다.