Hooks
: 함수 집합을 의미
함수 컴포넌트에서 생명주기 메소드 사용이 불가하기 때문에 상태 관리 및 랜더링 이후 시점 컨트롤 등 다양한 문제를 해결하기 위해 만들어졌다.
(리액트 16.8에서 새로 도입된 기능)
useState
: 가장 기본적인 hook, 함수 컴포넌트에서도 상태를 관리할 수 있게 해준다.
(useState 참조 : https://velog.io/@user01/react-state)
useEffect 랜더링 순서, 작성 위치 확인
const{ useEffect } = React;
function MessagePrinter(props){
console.log('랜더링...'); // 1번 동작
useEffect(() => {
console.log('랜더링 이후 동작...');
}); // 3번동작
return (
<h1>{ console.log('랜더링 시 출력') }{ props.message }</h1> // 2번 동작
);
/* 이 위치에서 무언가 동작하게하고 싶어도 작성할 수 없다.
render이후 실행하고 싶은 동작을 useEffect를 통해 처리할 수 있다. */
}
const message = "안녕하세요";
ReactDOM.createRoot(document.getElementById('root')).render(
<MessagePrinter message={ message }/>
);
위 코드를 실행한 console창
useEffect
: 기본적으로 마운트 된 시점, 업데이트 된 시점 두 가지 모두 동작
마운트 될 때만 동작하고 업데이트 시에는 동작하지 않게 컨트롤 할 수도 있다.
const { useState, useEffect } = React;
function TimePrinter() {
const [time, setTime] = useState(new Date().toLocaleTimeString());
useEffect(
() => { console.log('useEffect 동작...') },
[]
// 두번째 인자로 빈 배열을 넣으면 업데이트 시점에는 동작하지 않고
// 마운트 시점에만 동작하게 된다.
);
return (
<>
<button
onClick={ () => setTime(new Date().toLocaleTimeString()) }
>
현재 시간 확인하기
</button>
<h1>{ time }</h1>
</>
);
}
두번째 인자로 빈 배열 삽입 전
두번째 인자로 빈 배열 삽입 후
(업데이트 시에 동작하지 않는다.)
특정 값이 업데이트 될때만 실행하게 컨트롤
단, 업데이트 시에만 동작하는게 아니므로 최초 마운트 시점도 동작한다.
const { useState, useEffect } = React;
function LoginForm(){
const [user, setUser] = useState({
username : '',
password : ''
}); // user 초기화
const onChangeHandler = (e) => {
setUser({
...user,
[e.target.name] : e.target.value
});
}
useEffect(
() => {console.log('username update...')},
[user.username] // <h3></h3>에 반환
);
useEffect(
() => {console.log('password update...')},
[user.password] // <h3></h3>에 반환
);
return (
<>
<label>username :</label>
<input type="text" name="username" onChange={onChangeHandler}/><br/>
<label>password :</label>
<input type="password" name="password" onChange={onChangeHandler}/><br/>
<h3>username : { user.username }</h3>
<h3>password : { user.password }</h3>
</>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<LoginForm/>);
cleanup 함수 동작 순서 확인
useEffect는 기본적으로 랜더링 직후, 업데이트 직후 호출된다.
cleanup
: 컴포넌트가 마운트 해제되기 직전, 업데이트되기 직전에 실행할 내용이 있다면 정리(clean-up)를 하는 기능도 수행.
이전 effect 내용을 정리하고 난 뒤 새로운 effect가 동작하도록 할 때 사용.
이전 effect가 남아있는 상태에서 새로운 effect가 발생하면 메모리 누수나 충돌이 발생할 가능성이 있다.
(componentWillUnmount의 역할과 동일)
const { useState, useEffect } = React;
function Counter(){
const [ count, setCount ] = useState(0);
useEffect(() => {
console.log('useEffect 동작...');
/* 정리함수를 반환한다. */
return () => {
console.log('clean-up...');
}
});
return(
<>
<h1>count : { count }</h1>
<button onClick={ () => setCount( count + 1 ) }>+1</button>
</>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<Counter/>);
첫 실행시 useEffect 동작
예제)
컴포넌트 언마운트 시 setInterval 종료하는 함수 반환이 없다면, 메모리상에서 타이머는 계속 작동하게된다.
clearInterval함수로 종료 시켜준다.(cleanup동작)
const { useState, useEffect } = React;
function Timer() {
useEffect(
() => {
console.log('타이머가 시작합니다...');
const timer = setInterval(
() => {
console.log(new Date().toLocaleTimeString());
}, 1000
);
/* 컴포넌트 언마운트 시 setInterval 종료하는 함수 반환 */
return () => {
clearInterval(timer);
console.log('타이머가 종료 됩니다...');
}
},
[]
);
return <h1>타이머를 시작합니다.</h1>;
}
function App(){
const [isTrue, setIsTrue] = useState(false);
return (
<>
<button onClick={ ()=> setIsTrue(!isTrue) }>타이머 토글</button>
{ isTrue && <Timer/> }
</>
);
}