Hooks는 리액트 16.8에 새로 도입된 기능으로
함수형 컴포넌트
에서도 상태 관리를 할 수 있는useState
, 렌더링 직후 작업을 설정하는useEffect
등의 기능을 제공한다.
hooks
라는 프로젝트를 생성했다.$ yarn create react-app hooks
Hook
이며, 함수형 컴포넌트에서도 가변적인 상태를 지닐 수 있게 해준다고ㅓ 이해하자.src/Counter.js
파일의 코드로 useState 기능을 사용해서 숫자 카운터를 구현했다.//Counter.js
const Counter = () => {
const [value, setValue] = useState(0);
return (
<div>
<p>
현재 카운터 값은 <b>{value}</b>이다.
</p>
<button onClick={() => setValue(value +1)}>+1</button>
<button onClick={() => setValue(value -1)}>-1</button>
</div>
);
};
import 구문
을 통해 불러오고, 다음과 같이 사용한다.const [value, setValue] = useState(0);
배열
을 반환하는데, 그 배열
의 첫 번째 원소는 상태 값
, 두 번째 원소는 상태 설정하는 함수
이다.//Info.js
const Info = () => {
const [name, setName] = useState('');
const [nickname, setNickName] = useState('');
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>
<div>
<b>이름: </b> {name}
</div>
<div>
<b>닉네임: </b> {nickname}
</div>
</div>
</div>
);
};
렌더링
될 때마다 특정 작업을 수행하도록 설장하는 Hook
이다.componeneDidMount
와 componentDidUpdate
를 합친 형태로 생각하자.❗//EffectInfo.js
const Info = () => {
const [name, setName] = useState('');
const [nickname, setNickName] = useState('');
useEffect(() => {
console.log('렌더링 완료');
console.log({
name,
nickname
});
});
const onChangeName = e => {
setName(e.target.value);
};
const onChangeNickname = e => {
setName(e.target.value);
};
return (
<div>
<div>
<input value={name} onChange={onChangeName} />
<input value={nickname} onChange={onChangeNickname} />
</div>
<div>
<div>
<b>이름: </b> {name}
</div>
<div>
<b>닉네임: </b> {nickname}
</div>
</div>
</div>
);
};
컴포넌트
가 화면에 맨 처음 렌더링
될 때만 실행하고, 업데이트될 때는 실행하지 않으려면 함수의 두 번째 파라미터
로 비어있는 배열을 넣어주면 된다.useEffect(() => {
console.log('마운트될 때만 실행');
}, []);
useEffect(() => {
console.log(name);
}, [name]);
위의 코드와 같이 두 번째 파라미터로 전달되는 배열
안에 검사하고 싶은 값을 넣어주면 된다.
이해를 돕기위해 위의 코드를 클래스형 컴포넌트로 작성하면 아래 코드와 같다.
componentDidUpdate(prevProps, prevState) {
if(prevProps.value !== this.props.value) {
doSomething();
}
}
useEffect는
렌더링
되고 난 직후마다 실행되며, 두 번째 파라미터 배열에 무엇을 넣는지에 따라 실행되는 조건이 틀려지기 때문에 컴포넌트가언마운트
되기 전이나업데이트
되기 직전에 특정 작업을 수행하고 싶다면 useEffect에서cleanup
함수를 반환해야 한다.
useEffect(() => {
console.log('effect');
console.log(name);
return () => {
console.log('cleanup');
console.log(name);
};
});
Hook
이다.액션(action)
값을 전달받아 새로운 상태를 반환하는 함수이다.불변성
을 지켜야한다.function reducer(state, action) {
return {...}; // 👉 불변성을 지키면서 업데이트한 새로운 상태를 반환
}
액션 객체
는 반드시 type
을 가질 필요도 없고, 객체
가 아닌 문자열
이나 숫자
여도 상관없다.{
type: 'INCREMENT',
// 👉 다른 값들이 필요하면 추가 (ex. DECREMENT 등등)
}
src/Counter.js
파일을 useReducer를 사용하여 새로운 컴포넌트를 생성하는 코드이다.// ReducerCounter.js
function reducer(state, action) {
// action.type에 따라 작업 수행
switch (action.type) {
case 'INCREMENT':
return { value: state.value + 1 };
case 'DECREMENT':
return { value: state.value - 1 };
default:
// 아무것도 해당 안되면 기존 상태 반환
return state;
}
}
const ReducerCounter = () => {
const [state, dispatch] = useReducer(reducer, { value: 0 });
return (
<div>
<p>
현재 카운터 값은 <b>{state.value}</b>이다.
</p>
<button onClick={() => dispatch({ type: 'INCREMENT'})}>+1</button>
<button onClick={() => dispatch({ type: 'DECREMENT'})}>-1</button>
</div>
);
};
리듀서 함수
를 넣고, 두 번째 파라미터에는 해당 리듀서의 기본값
을 넣어 사용한다.state
값과 dispatch
함수를 받아오는데, 여기서 state
는 현재 가르키고 있는 상태이고, dispatch
는 액션을 발생시키는 함수이다.dispatch(action)
의 형태로 리듀서 함수가 호출되는 구조 ✔Input
상태를 관리하는 코드이다.Input
이 여러 개여서 useState
를 여러 번 사용했는데, useReducer
를 사용하면 기존에 클래스형 컴포넌트에서 input
태그에 name
값을 할당하고, e.target.name
을 참조해서 setState
를 해 준 것과 비슷하게 처리할 수 있다.//InputInfo.js
function reducer(state, action) {
return {
...state,
[action.name]: action.value
};
}
const InputInfo = () => {
const [state, dispatch] = useReducer(reducer, {
name: '',
nickname: ''
});
const { name, nickname } = state;
const onChange = e => {
dispatch(e.target);
};
return (
<div>
<div>
<input name="name" value={name} onChange={onChange} />
<input name="nickname" value={nickname} onChange={onChange} />
</div>
<div>
<div>
<b>이름: </b> {name}
</div>
<div>
<b>닉네임: </b> {nickname}
</div>
</div>
</div>
);
};
액션
은 어떤 값을 사용하든 상관없다.e.target
값 자체를 액션 값
으로 사용한 코드이다.Hook을 시작하면서 이제 드디어 리액트
를 맛보는 느낌이다.
아직 조금 어색하긴 하지만 target
, dispatch
, reducer
헷갈리지 않게 반복적으로 공부하자.😊❗