[ Hook 란? ]
클래스형 컴포넌트에서만 사용 가능했던 state 와 lifecycle 을 함수형 컴포넌트에서도 사용 가능하도록 도와주는 기능
[ Hooks 종류 ]
1. useState()
Hook 으로 함수형 컴포넌트에서 가변적인 상태를 지니게 해준다.Stateimport React, { useState } from 'react';
function StateFunction() {
// [state명, setter함수] = useState(초기값)
// useState의 초기값은 숫자일 수도, 문자일 수도, 배열일 수도 있다.
const [msg, setMsg] = useState("");
const [list, setList] = useState([]);
function changeMsg() {
setMsg("메세지");
}
return (
<div>
<p>{msg}</p>
<button onClick={changeMsg}>클릭</button>
</div>
)
}
export default StateFunction;
2. useEffect()
componentDidMount 와 componentDidUpdate 가 합쳐진 형태import {useState, useEffect} from 'react';
const Hook = () => {
const [name, setName] = useState("");
const [cnt, setCnt] = useState(0);
const changeName = e => {
setName(e.target.value);
}
const changeCnt = () => {
setCnt(cnt + 1);
}
// 컴포넌트가 rendering 될 때마다 특정 작업을 수행
useEffect(() => {
console.log("렌더링이 완료되었습니다.");
})
// 두번째 인자로 빈 배열을 보내면, Mount 될 때만 실행된다.
useEffect(() => {
console.log("최초 rendering");
}, [])
// 특정 값이 바뀔 때만 실행하고 싶다면, 배열에 값을 넣어주면 된다.
// Mount 될 때는 항상 실행된다.
useEffect(() => {
console.log('name값 변경');
// cleanup(뒷정리) 함수 : 렌더링 되기 직전에 실행된다.
return () => {
console.log("name2 : ", name);
}
}, [name])
return(
<div>
<div>
<input value={name} onChange={changeName}></input>
<button onClick={changeCnt}>+1</button>
</div>
<h3>이름 : {name}</h3>
<h3>횟수 : {cnt}</h3>
</div>
)
}
export default Hook;
3. useReducer()
useState() 처럼 State 를 관리할 수 있게 해준다.useReducer() 를 사용하면 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있다.import {useReducer} from 'react';
// reducer() : 현재 상태와 업데이트를 위해 필요한 정보를 담은 액션 값을 전달받아 새로운 상태를 반환하는 함수
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return {value: state.value + 1};
case "DECREMENT":
return {value: state.value - 1};
default:
return state;
}
}
const Reducer = () => {
// useReducer(reducer 함수, 초기값) -> state.value = 0
const [state, dispatch] = useReducer(reducer, {value: 0});
// state = 현재 가리키고 있는 상태
// dispatch = 액션을 발생시키는 함수
return(
<div>
<h1>{state.value}</h1>
{/* dispatch 함수 실행 */}
<button onClick={() => {dispatch({type: "DECREMENT"})}}>-1</button>
<button onClick={() => {dispatch({type: "INCREMENT"})}}>+1</button>
</div>
)
}
export default Reducer;
4. useMemo()
HookRendering 과정에서 특정 값이 바뀌었을 때만 연산을 실행한다.import {useState, useMemo} from 'react';
function getAverage(list) {
console.log("getAverage");
let sum = 0;
if (list.length == 0) return sum;
for (let i=0; i<list.length; i++) {
sum = sum + list[i];
}
return sum / list.length;
}
const Memo = () => {
const [list, setList] = useState([]);
const [num, setNum] = useState("");
// input창에 입력될 때마다 State가 업데이트 된다.
const onChange = e => {
console.log("onChange");
setNum(e.target.value);
}
const onInsert = e => {
setList([...list, parseInt(num)]);
setNum(0);
}
// State가 업데이트 되어 재렌더링 될 때마다 함수가 재선언되어 getAverage 함수가 계속 실행된다.
const avg = getAverage(list);
// useMemo() 사용
// list값이 업데이트 됐을 때만 getAverage 함수가 실행된다.
const avg = useMemo(() => {getAverage(list)}, [list]);
return(
<div>
<input value={num} onChange={onChange}/>
<button onClick={onInsert}>등록</button>
<ul>
{list.map((v, i) => {
<li key={i}>{v}</li>
})}
</ul>
<div>
<b>평균값 : {avg}</b>
</div>
</div>
)
}
export default Memo;
5. useCallback()
Rendering 최적화에 사용되는 Hook APIimport {useState, useCallback} from 'react';
// 위의 onChange 함수와 onInsert함수에 useCallback을 사용하였다.
// onChange함수에서는 State가 사용되지 않았기 때문에 빈 배열을 보내 Mount 될 때만 함수가 선언되게 해주었다.
const onChange = useCallback(e => {
console.log(e.target.value);
setNum(e.target.value);
}, []);
// onInsert함수에서는 num과 list가 사용되었기 때문에 num과 list값이 업데이트 될 때마다 해당 함수가 필수로 재선언되어야 한다.
const onInsert = useCallback(e => {
setList([...list, parseInt(num)]);
setNum("");
}, [num, list]);
6. useRef()
ref 를 사용하기 쉽게 만들어주는 Hookimport {useRef} from 'react';
const Ref = () => {
// useRef(초기값) : 보통 useRef(null)
const input = useRef();
const onInsert = e => {
// ref.current로 현재 가리키는 객체에 접근할 수 있다.
input.current.focus();
}
return(
<div>
// ref={}
<input value={num} onChange={onChange} ref={input}/>
<button onClick={onInsert}>등록</button>
<ul>
{list.map((v, i) => {
<li key={i}>{v}</li>
})}
</ul>
<div>
<b>평균값 : {avg}</b>
</div>
</div>
)
}
export default Ref;