/ React Hooks 란?
리액트 v16.8로 업데이트 되면서 함수형 컴포넌트와 Hooks 사용을 권장하고 있다.
Hook은 함수형컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 연동(hook into)할 수 있게 해주는 함수이다. 클래스형 컴포넌트 안에서는 동작하지 않지만 클래스형 컴포넌트없이 리액트를 사용할 수 있게 해준다.
장점
- 컴포넌트로부터 상태 관련 로직을 추상화할 수 있다.
- 생명주기를 사용했을때 일어나는 버그와 무결성 문제를 보완할 수 있다.
- 클래스형 컴포넌트의 this로 인한 혼동과 코드양을 줄인다.
/ 함수형 컴포넌트
import React from 'react';
const App = () => {
return(
<h1>안녕하세요!</h1>
)
}
export default App;
es6기반 함수형 컴포넌트의 기본 형태이다.
상세설명은 [React] 함수형 컴포넌트 포스팅 참고
/ Hooks
1. useState()
useState는 상태값, 메소드가 담긴 배열을 반환하며, 초기값을 설정할 수 있다.
// useState의 반환값을 userState변수에 저장.
const userState = useState(0);
console.log(userState); // 출력값 [0,메소드] = [상태값, 메소드]
위의 코드에 기초해 구조분해할당(Destructuring assignment)을 통해 다시 표현하면
[상태값, 메소드] = useState(기본값) 이다.
state에 해당하는 부분이 배열 첫번째의 상태값이고, setState를 해주는 부분이 배열 두번째 값인 메소드이다.
아래는 useState를 사용하여 버튼을 클릭할 때마다 숫자가 1씩 증가하는 예시코드이다.
import React, { useState } from 'react';
const Counter = () => {
const [count,setCount] = useState(0);
const countFunction = () => {
setCount(count+1)
};
return(
<div>
<p>You Clicked {count} times!</p>
<button onClick={countFunction}>Click me</button>
</div>
)
}
export default Counter;
Click me버튼을 클릭하면 countFunction이 실행된다.
countFunction은 setCount를 이용하여 useState의 count상태를 1증가 시킨다.
즉 useState에서 반환하는 메서드는 상태를 업데이트한다.
2. useEffect()
useEffect는 컴포넌트에서 side effects를 수행한다.
기존에 React lifecyle 내에서 사용했던 로직을 useEffect를 이용해 구현할 수 있다.
(데이터 fetch, subscription 설정, DOM 수정 등)
clean-up함수가 필요하지 않은 경우와 필요한 경우로 크게 두가지의 경우로 구분할 수 있다.
2-1. clean-up 함수가 필요하지 않은 경우
기본 형태는 useEffect( effect, [상태값1, 상태값2 ...]) 로
두번째 인자에 명시한 상태값이 변할때마다, 즉 랜더링될 때마다 수행된다.
이 배열을 삭제하거나 null로 두면 모든 상태값이 변화할 때마다 useEffect는 실행된다.
반면 빈 배열을 넣으면 최초랜더링 시에만 useEffect가 실행된다.
lifecyle에 익숙하다면 componentDidMount와 componentDidUpdate에서 실행된다고 생각할수 있겠다.
import React, { useState, useEffect} from 'react';
const Counter = () => {
const [countA,setCountA] = useState(0);
const setCountAFunction = () => {
setCountA(countA+1)
};
const [countB,setCountB] = useState(0);
const setCountBFunction = () => {
setCountB(countB-1)
};
// case1 : 최초 랜더링시에만 실행(componentDidMount)
useEffect(() => {
console.log(`initial count ${countA}, ${countB}`);
},[]);
// case2 : countA의 상태변화에 따라 실행
useEffect(() => {
console.log(`countA : ${countA}`);
},[countA]);
// case3 : 모든 상태변화에 따라 실행(componentDidMount + componentDidUpdate)
useEffect(() => {
console.log(`countA : ${countA} countB : ${countB}`);
},null);
return(
<div>
<p>Number increase : {countA}</p>
<button onClick={setCountAFunction}>Click me</button>
<p>Number decrease : {countB}</p>
<button onClick={setCountBFunction}>Click me</button>
</div>
)
}
export default Counter;
2-2. clean-up 함수가 필요한 경우
기본 형태인 useEffect(effect, [상태값1, 상태값2 ...])에서 effect에 정리가 필요한 경우라면 effect가 함수를 리턴하게하면 된다. (ex.메모리누수방지, 데이터 초기화 등 의 상황 )
그리고 그 때 리턴되는 함수를 clean-up함수라고 한다.
effect의 리턴값이 함수라면 리액트는 그 함수를 정리가 필요한 때에 실행시킨다.
(리액트 lifecycle의 componentWillUnmount에 해당한다고 생각하면 된다.)
import React, { useState, useEffect} from 'react';
const Counter = () => {
const [countA,setCountA] = useState(0);
const setCountAFunction = () => {
setCountA(countA+1)
};
const [countB,setCountB] = useState(0);
const setCountBFunction = () => {
setCountB(countB-1)
};
useEffect(() =>{
console.log(`${countA} , ${countB}`);
console.log('effect',new Date().getMilliseconds())
// 이하 clean-up함수
return ()=>{
console.log(`${countA} , ${countB}`);
console.log('clean-up',new Date().getMilliseconds())
}
},null);
return(
<div>
<p>Number increase : {countA}</p>
<button onClick={setCountAFunction}>Click me</button>
<p>Number decrease : {countB}</p>
<button onClick={setCountBFunction}>Click me</button>
</div>
)
}
export default Counter;
아래의 이미지는 위 코드의 실행결과인데,
clean-up함수와 effect의 실행 시점을 확인하기위해 콘솔에 milliseconds를 함께 찍어보았다.
clean-up 함수가 실행된 후 바로 effect가 발생하는것을 확인할수 있다.
더불어 clean-up은 방금 실행된 effect의 이전 effect 상태를 반영하기때문에 2가 찍혀있고,
effect는 상태변화를 반영했으므로 3이 찍혀있는것을 확인할 수 있다.
즉 정확한 시점은 리액트가 다음 차례의 effect를 실행하기 전,
이전의 렌더링에서 파생된 effect를 정리할때 실행되는 것이다.
그럼 기존 lifecycle의 componentDidUpdate 해당하는 것은? 이라고 생각한다면,
기본적으로 useEffect는 업데이트를 다루기 때문에 그 자체로 충분하다고 알아두자.
| 함께 읽어두면 좋은 포스팅
'개발공부 > React' 카테고리의 다른 글
[React] 리액트(CRA) 프로젝트 세팅하기 - typescript, alias, emotion (1) | 2021.10.21 |
---|---|
[React] 리액트 인라인 스타일 적용 (0) | 2019.10.27 |