728x90
1.Hooks란?
함수형 컴포넌트에서 React의 state와 lifecycle을 연동할 수 있게 해주는 함수이다.
즉, 클래스형 컴포넌트의 기능을 함수형 컴포넌트에서 사용할 수 있도록 해주는 기능으로,
이 기능이 있기에 이제 클래스형 컴포넌트를 함수형 컴포넌트가 완전히 대체할 수 있게 되었다.
가.사용 규칙
공식 문서에 따르면 Hook의 사용 규칙은 두가지이다.
https://ko.legacy.reactjs.org/docs/hooks-rules.html#explanation
✅ 첫번째, 함수형 컴포넌트에서만 Hook를 사용할 수 있다.
당연하다. 클래스형 컴포넌트는 이미 내장 모듈이 있고
이걸 함수형 컴포넌트에서 사용하기 위해 만든 것이므로, 함수형 컴포넌트에서 사용해야한다.
✅ 두번째, 최상위에서만 Hook을 호출해야한다.
즉, 반복문, 조건문 또는 중첩된 함수 내에서 호출하면 안된다.
쉽게 말하면 들여쓰기 맨앞에서 호출되어야한다.
(최상위 호출이라고 해서 최상위 컴포넌트에서 호출되어야한다는 의미가 아니다.)
아래 예시를 보자
잘못된 예시 : 조건문 안에 Hook을 사용해서 두번째 규칙을 어겼다.
if (name !== '') {
useEffect(function persistForm() {
localStorage.setItem('formData', name);
});
}
수정된 예시: 만약 if문을 써야한다면 useEffect 내에 작성하자.
useEffect(function persistForm() {
// 👍 더 이상 첫 번째 규칙을 어기지 않습니다
if (name !== '') {
localStorage.setItem('formData', name);
}
});
나.Hooks 종류
- useState()
- 함수형 컴포넌트에서 상태 관리를 위해 사용
- 동적 상태 관리
- 가장 기본적인 Hook으로 함수형 컴포넌트에서 가변적인 상태를 지니게 해준다.
- 클래스형 컴포넌트에서의 State와 동일하다.
- 사용방법: const [message,setMessage] = useState("")
- useEffect()
- sideEffect(부수효과; mount/ unmount/ update)를 수행한다.
- 클래스형 컴포넌트의 componentDidMount와 componentDidUpdate가 합쳐진 형태이다.
- 사용방법:
- Mount & Update될 때 : useEffect(()=>{})
- Mount될 때만 (최초 렌더시) : useEffect(()=>{},[])
- 특정 값 Update시에 만: useEffect(()=>{},[data])
- Updata 직전 수행: useEffect(()=>{ return()=>{};}), cleanup(뒷정리 함수) 사용
- useRef()
- 함수형 컴포넌트에서 ref를 사용하기 쉽게 만들어주는 Hook
- useRef()는 인자로 받은 값으로 초기화된 변경 가능한 ref객체를 반환한다.
- ref.current로 현재 가리키는 객체에 접근할 수 있다.
- 용도: 1) DOM요소 접근 2)로컬 변수로 사용
- 사용 방법
- DOM요소 접근:
- const myRef = useRef();
- <element> ref = {myRef}</element>
- myRef.current;
- 로컬 변수로 사용:
- const myRef = useRef(초기값);
- DOM요소 접근:
- useMemo()
- 함수형 컴포넌트 내부에서 발생하는 연산을 최적화시켜주는 Hook
- Rendering과정에서 특정값이 바뀌었을 때만 연산을 실행한다.
- Rendering과정에서 두번째 인자로 받은 의존 배열(dependency) 내 값이 바뀌는 경우에만 첫번째 인자로 받은 콜백함수를 실행해 구한 값을 반환한다.
- 사용 방법: const memoizedValue = useMemo(callback, dependency);
- useCallback()
- Rendering 최적화에 사용되는 Hook
- useMemo와 유사하나, useMemo는 값을 최적화한다면, useCallback()은 다시 rendering될 때 함수를 다시 불러오는 것을 막는다.
- 사용 방법: const memoizedCallback = useCallback(callback, dependency);
- useReducer()
- Reducer란? 현재 상태와 업데이트를 위해 필요한 정보를 담은 액션 값을 전달받아 새로운 상태를 반환하는 함수이다.
- useReducer를 사용하면 컴포넌트 업데이트 로직을 컴포넌트 외부로 뺄 수 있다.
- 또한 useState를 대체하여 다양한 컴포넌트 상황에 따라 상태값을 설정할 수 있다.
- useReducer가 useState 기반이기는 하지만 더 좋은것은 아니고, 상황에 따라 더 맞는 hook을 설정하자.
- state가 단순하다 => useState사용
- state가 복잡하다 => useReducer사용 //객체,배열 등 하위 요소 많은 경우
- 사용 방법:
- Reducer 정의: const [state, dispatch] = useReducer(reducer, initialState)
- dispatch 함수로 action값 전달: dispatch는 action값을 전달 받아 state와 함께 Reducer에 전달
- <button onClick={()=>dispatch('INCREMENT')}>Plus</button>
- Reducer: 현재 state와 action값을 전달 받아 새로운 state 반환
- const reducer = (prevNumber,action) => {switch (action){ case 'INCREMENT': return prevNumber+1; default: return prevNumber;}}
2.예제
예제를 통해 이전 포스팅에서 다뤄보지 못했던 useMemo(), useCallback(). useReducer()에 관해 알아보자.
가.useMemo()
import { useState, useMemo } from "react";
//평균값 계산 함수
//숫자를 [등록] 버튼을 틀릭할 때 뿐만 아니라
//input내용을 수정할 때도 getAverage함수가 호출되고 있음
// ('평균값 계산중 ..!')이 input 내용 수정할 떄마다 콘솔에 출력됨
//=> useMemo를 사용해서 최적화할 수 있음 , 등록 버튼만 눌렀을 떄 실행 되도록
const getAverage = (numbers) => {
//numbers: 숫자 저장하고 있는 배열
console.log("평균값 계산중 ...!");
//만약 numbers 배열에 원소가 없다면 평균값은0
if (numbers.length === 0) return 0;
// numbers 배열에 모든 원소 더함
const sum = numbers.reduce((a, b) => a + b);
// 평균값을 계산하여 반환
return sum / numbers.length;
};
const useMemoTest = () => {
const [number, setNumber] = useState("");
const [list, setList] = useState([]);
const onChange = (e) => {
setNumber(e.target.value);
};
const onInsert = () => {
const newList = list.concat(parseInt(number));
setList(newList);
setNumber("");
};
// [after] useMemo hook 적용
// 랜더링 과정에서 list 값이 변경될 때만 callback 함수를 실행 => [list]
// useMemo() 요약
// '수행한 연산의 결과 값을 기억' 함으로써 계산을 최소화함
const avg = useMemo(() => {
return getAverage(list);
}, [list]);
return (
<>
<h1>useMemo hook</h1>
<input type="number" value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((li, idx) => {
return <li key={idx}>{li}</li>;
})}
</ul>
{/* useMemo 사용전: <h1>평균값 : {getAverage(list)}</h1> */}
<h1>평균값 : {avg}</h1>
</>
);
};
export default useMemoTest;
나.useCallback()
import { useState, useCallback } from "react";
const useCallbackTest = () => {
const [text, setText] = useState("");
// 매번 전체 렌더링 ->onChangeText다시 만듦
// useCallback 사용시 함수 저장해서 다시 만들지 않도록함
// useCallback()
// 반복해서 생성되는 이벤트 핸들러 함수를 useCallback으로 감싸주면
// 함수를 메모이제이션(기억)해서 컴포넌트가 다시 랜더링되더라도
// 기억하고 있는 기존 함수를 그대로 사용
// 실행 결과가 같으나 내부적으로 성능은 향상됨
// useCallback vs useMemo
// const memoizedCallback = useCallback(function,deps)
// const memoizedValue = useMemo(() => function,deps)
// useCallback: useMemo를 기반으로 만든 hook
// 단, "함수를 사용할 때" 편의성을 증진시킨 hook
//공통점: 성능 최적화
//차이점:
// - useMemo: "값"을 재사용
// => 값의 재사용을 위해 전달된 함수를 실행하고 "그 결과"를 메모이제이션
// - useCallback: "함수"를 재사용
// => "함수의 재사용"을 위해 전달된 "함수 자체"를 메모이제이션
const onChangeText = useCallback((e) => {
setText(e.target.value);
}, []);
return (
<>
<h1>UseCallback hook</h1>
<input onChange={onChangeText} />
<h2>작성한값:{text || "없음"}</h2>
</>
);
};
export default useCallbackTest;
다.useReducer()
import { useReducer } from "react";
const reducer = (prevNumber, action) => {
//prevNumber: 현재 state
//action: dispatch에서 인자로 받고 있는 현재 액션 값
switch (
action.type // {type: 'xx}
) {
case "INCREMENT":
return { value: prevNumber.value + 1 };
case "DECREMENT":
return { value: prevNumber.value - 1 };
case "RESET":
return { value: 7 };
default:
return { value: prevNumber.value };
}
};
const UseReducerTest = () => {
const [number, dispatch] = useReducer(reducer, { value: 7 });
const increment = () => {
dispatch({ type: "INCREMENT" });
};
const decrement = () => {
dispatch({ type: "DECREMENT" });
};
const reset = () => {
dispatch({ type: "RESET" });
};
return (
<>
<h1>useReducer hook</h1>
<h2>{number.value}</h2>
<button onClick={increment}>Plus</button>
<button onClick={decrement}>Minus</button>
<button onClick={reset}>Reset</button>
</>
);
};
export default UseReducerTest;
728x90
'프론트앤드 > React' 카테고리의 다른 글
[포스코x코딩온] 웹개발자 입문 과정 9주차 | Sass (0) | 2023.05.07 |
---|---|
[포스코x코딩온] 웹개발자 입문 과정 8주차 | Life Cycle (0) | 2023.05.02 |
[포스코x코딩온] 웹개발자 입문 과정 8주차 | ref (0) | 2023.04.27 |
[포스코x코딩온] 웹개발자 입문 과정 8주차 | map & filter (0) | 2023.04.26 |
[포스코x코딩온] 웹개발자 입문 과정 8주차 | 이벤트 핸들링 (0) | 2023.04.25 |