Hook은 리액트 16.8 버전에 새롭게 추가된 기능입니다. Hook이 추가되면서 클래스형 컴포넌트를 작성하지 않고도 함수형 컴포넌트내에서 상태를 관리할 수 있게 되었고, 추가적인 기능들을 제공하게 되었습니다.
useState는 가장많이 사용되는 Hook 중 하나일 것입니다. useState의 등장으로 인하여 함수형 컴포넌트 내에서도 상태를 관리할 수 있게 되었습니다.
useState
의 파라미터로 초기값을 넣어줍니다. 이 초기값은 첫 번째 렌더링시 한번만 사용됩니다. useState
을 호출하면 배열을 반환합니다. 첫번째 값으로는 상태 값, 두번째 값으로는 상태 값을 변경시킬 수 있는 setter를 반환합니다.
const [value, setValue] = useState(initialState);
상태 값으로는 배열, 객체, 숫자 등 어떠한 것이든 가능합니다. 클래스형 컴포넌트처럼 하나의 객체에서 상태를 관리해도 되고, 여러 state 변수를 선언해서 사용해도 됩니다.
const [state, setState] = useState({
name: '',
nickname: ''
});
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
useEffect
는 컴포넌트가 렌더링 될때마다 특정 기능을 수행하도록 할때 사용합니다. useEffect
를 호출할때 첫번째 파라미터로 함수를 넘겨주면 렌더링 될때 해당 함수가 호출이 됩니다.
useEffect
는 DOM이 모두 그려진 후에 호출된다.
두번째 파라미터를 넘겨주지 않고 첫번째 파라미터만 함수를 제공한다면, 렌더링이 될때마다 해당 함수가 호출이 됩니다.
아래의 코드를 작성 후 input의 값을 변경 시킬때마다 콘솔이 찍히는 걸 확인할 수 있습니다.
const Info = () => {
const [name, setName] = useState('');
const onChangeName = e => setName(e.target.value);
useEffect(() => {
console.log(name);
});
return (
<div>
<input value={name} onChange={onChangeName}/>
<div>{name}</div>
</div>
)
};
export default Info;
useEffect
는 두번째 파라미터로 배열을 받습니다. 이때, 빈배열을 두번째 파라미터로 넘겨주면 컴포넌트가 마운트 될때 딱 1번만 호출되게 됩니다.
const Info = () => {
useEffect(() => {
console.log('마운트 될때 1번만 호출하기');
}, []);
return (
<div>
한번만 호출하기
</div>
)
}
export default Info;
useEffect
의 두번째 파라미터로 배열을 넘길때, 특정 상태값을 포함하여 넘겨주면 됩니다.
아래와 같이 배열에 name을 포함하여 넘겨주면, name 상태값이 바뀔 때만 호출되게 됩니다.
const Info = () => {
const [name, setName] = useState('');
const onChangeName = e => setName(e.target.value);
useEffect(() => {
console.log(name);
}, [name]);
return (
<div>
<input value={name} onChange={onChangeName}/>
<div>{name}</div>
</div>
)
};
export default Info;
컴포넌트가 언마운트 되거나, 컴포넌트가 리렌더링 되기 전에 코드를 실행해야할 경우가 존재합니다. 이럴 때 Clean-up을 사용할 수 있습니다.
Clean-up
을 사용하는 방법은 useEffect
함수 내부에서 Clean-up
함수를 반환해주면 됩니다.
useEffect(() => {
return () => {
// Clean-up 코드가 들어갈 부분
}
});
useEffect
의 두번째 파라미터를 넘겨주지 않고, Clean-up
함수를 반환해주면 됩니다.
const Info = () => {
const [name, setName] = useState('');
const onChangeName = e => setName(e.target.value);
useEffect(() => {
return () => {
console.log(name);
}
});
return (
<div>
<input value={name} onChange={onChangeName}/>
<div>{name}</div>
</div>
)
};
export default Info;
컴포넌트가 언마운트될 때 한번만 호출하는 방법은 마운트 될때 1번 호출하는 방법과 유사합니다. 두번째 인자로 빈배열을 넘겨주고, Clean-up
함수를 반환해주면 됩니다.
const Info = () => {
useEffect(() => {
return () => {
console.log('언마운트 될때 1번만 호출하기');
}
}, []);
return (
<div>
한번만 호출하기
</div>
)
}
export default Info;
useEffect
의 두번째 파라미터로 배열을 넘길때, 특정 상태값을 포함하여 넘겨주고 Clean-up
함수를 반환해주면 됩니다.
const Info = () => {
const [name, setName] = useState('');
const onChangeName = e => setName(e.target.value);
useEffect(() => {
return () => {
console.log(name);
}
}, [name]);
return (
<div>
<input value={name} onChange={onChangeName}/>
<div>{name}</div>
</div>
)
};
export default Info;
Clean-up
시에 사용하는 상태값을 배열에 포함시키지 않는 경우 현재 값이 아닌 이전 렌더링 때의 값을 참고하게 됩니다.
테스트 결과 Clean-up
함수가 아닌 곳에서는 정상적으로 현재값이 출력되는 것을 확인하였습니다.
아래와 같이 코드를 작성하고 먼저 name을 변경 후에 nickname을 변경하면, 현재 값이 아닌 이전 렌더링 값이 출력되는 것을 확인할 수 있습니다.
const Info = () => {
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
const onChangeName = e => setName(e.target.value);
const onChangeNickname = e => setNickname(e.target.value);
useEffect(() => {
return () => {
console.log(name);
}
}, [nickname]);
return (
<div>
<input value={name} onChange={onChangeName}/>
<input value={nickname} onChange={setNickname}/>
<div>{name}</div>
<div>{nickname}</div>
</div>
)
};
export default Info;
아래의 코드를 작성 후, 동일하게 name을 변경 후에 nickname을 변경하면 name이 현재값으로 렌더링 되는 것을 확인할 수 있습니다.
const Info = () => {
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
const onChangeName = e => setName(e.target.value);
const onChangeNickname = e => setNickname(e.target.value);
useEffect(() => {
return () => {
console.log(name);
}
}, [nickname, name]);
return (
<div>
<input value={name} onChange={onChangeName}/>
<input value={nickname} onChange={setNickname}/>
<div>{name}</div>
<div>{nickname}</div>
</div>
)
};
export default Info;
name
을 변경하는 경우에는 이전 렌더링 결과가 출력됩니다.