Hooks는 리액트 v16.8에 새로 도입된 기능으로 함수컴포넌트에서도 상태 관리를 할 수 있는 useState, 렌더링 직후 작업을 설정하는 useEffect 등의 기능을 제공하여 기존의 함수 컴포넌트에서 할 수 없었던 다양한 작업을 할수 있게 해준다.
useState는 가장 기본적인 Hook이며, 함수 컴포넌트에서도 가변적인 상태를 지닐 수 있게 해준다.
import React, { useState } from 'react';
//Hook를 쓸때에는 꼭 사용할 훅을 임포트해와야함!
const Counter = () => {
const [value, setValue] = useState(0);
//위 코드는 배열 비구조화 할당으로 배열안의 원소를 새로운 이름으로 가져온것이다.
//const useState = [상태값, 상태설정함수]; 이렇게 된 배열을 위와같이 가져온것!
//상태값에는 다양한 타입의 값이 들어갈 수 있다.
return (
<div>
<p>현재 카운터 값은 <b>{value}</b>입니다.<p>
<button onClick={() => setValue(value + 1)}>+1</button>
<button onClick={() => setValue(value - 1)}>-1</button>
</div>
)
}
export default Counter;
useState 함수의 파라미터에는 상태의 기본값을 넣어 준다. 위 코드는 기본값을 0으로 설정한 것이다. 이 함수가 호출되면 배열을 반환하는데, 그 배열의 첫 번째 원소(value)는 상태 값, 두 번째 원소(setValue)는 상태를 설정하는 함수이다. 이 함수에 파라미터를 넣어서 호출하면 전달받은 파라미터로 값이 바뀌고 컴포넌트가 리렌더링 된다.
useEffect는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다. 클래스형 컴포넌트의 componentDidMount와 componentDidUpdate를 합친 형태로 보아도 무방하다.
import React, { useState, useEffect } from 'react';
const Info = () => {
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
ustEffect(() => {
console.log('렌더링 완료');
console.log({
name,
nickname
});
});
const onChangeName = e => {
setName(e.target.value);
};
const onChangeNickname = e => {
setNickname(e.target.value);
};
return (
<div>
<div>
<input value={name} onChange={onChangeName}/>
<input value={nickname} onChange={onChangeNickname}/>
</div>
<div>
<b>이름:</b> {name}
</div>
<div>
<b>닉네임:</b> {nickname}
</div>
</div>
)
}
export default Info;
useEffect에서 설정한 함수를 컴포넌트가 화면에 맨 처음 렌더링 될때만 실행하고, 업데이트될 때는 실행하지 않으려면 함수의 두번 째 파라미터로 비어있는 배열을 넣어주면 된다.
ustEffect(() => {
console.log('마운트될 때만 실행');
}, []);
위와 반대로 특정 값이 변경될 때만 호출하고 싶을 경우에는 useEffect의 두 번째 파라미터로 전달되는 배열 안에 검사하고 싶은 값을 넣어주면 된다. 수정하자면 아래와 같다.
ustEffect(() => {
console.log(name);
}, [name]);
배열안에는 useState를 통해 관리하고 있는 상태를 넣어 주어도 되고, props로 전달받은 값을 넣어 주어도 된다.
useMemo를 사용하면 함수 컴포넌트 내부에서 발생하는 연산을 최적화 할 수 있다.
예를 들어 평균값을 구하는 코드를 짰을 때, 인풋에 숫자를 등록할 때뿐만 아니라, 인풋내용이 수정될 때도 함수가 호출될 것이다. useMemo Hook를 사용해 이런식의 작업을 최적화할 수 있다. 렌더링 하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행하고, 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용하는 방식이다.
import { useState, useMemo } from 'react';
//들어온 값의 평균값을 구하는 함수
const getAverage = numbers => {
console.log('평균값 계산 중');
if(numbers.length === 0 ) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
}
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
const onChange = e => {
setNumber(e.target.value);
};
//인풋에 들어온 값을 등록버튼 누를때 배열에 연결하여 넣어주기
const onInsert = () => {
//배열을 변경해야 할때는 꼭 새로운 배열을 만들어 값을 없데이트시켜주기
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
};
//list값이 업데이트 될때만 실행되게 하기 위해 두번째 파라미터에 [list]를 넣어줌
const avg = useMeno(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange}/>
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) =>(
//리액트에서 배열만들때에는 key props는 필수!
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>평균값:</b> {avg}
</div>
</div>
);
};
export default Average;
useCallBack은 useMemo와 비슷한 함수이다. 주로 렌더링성능을 최적화해야 하는 상황에서 사용한다. 이 Hook을 하숑하면 만들어 놨던 함수를 재사용할 수 있다. 위에 만든 onChange와 onInsert함수는 컴포넌트가 리렌더링 될때마다 새로 만들어진 함수를 사용하게 된다. 그것을 최적화 시켜보자.
import { useState, useMemo, useCallback } from 'react';
const getAverage = numbers => {
console.log('평균값 계산 중');
if(numbers.length === 0 ) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
}
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
//useCallBack를 사용해 최적화! 컴포넌트가 처음 렌더링 될때만 함수 생성
const onChange = useCallback(e => {
setNumber(e.target.value);
}, []);
//useCallBack를 사용해 최적화! number, list가 바뀌었을 때만 함수 생성
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
}, [number, list]);
const avg = useMeno(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange}/>
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) =>(
//리액트에서 배열만들때에는 key props는 필수!
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>평균값:</b> {avg}
</div>
</div>
);
};
export default Average;
useCallback의 첫 번째 파라미터에는 생성하고 싶은 함수를 넣고, 두 번째 파라미터에는 배열을 넣으면 된다. 이 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지 명시해야 한다. 함수내부에서 상태 값에 의존해야 할 때는 그 값을 반드시 두 번째 파라미터 안에 포함시켜 주어야한다.
리액트를 다루는 기술을 읽고 요약한 글 입니다😊