리액트팀에서 React Hook을 발표했는데 함수형 컴포넌트에서도 이제 state와 side-effect를 적용 가능하게 되었습니다. 기본적으로 제공하는 Hook부터 커스텀 Hook까지 살펴보도록 하겠습니다.
-
`useState` Hook : 컴포넌트의 state관리
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
};
}
onChange = event => {
this.setState({ value: event.target.value });
};
render() {
return (
<div>
<h1>Hello React ES6 Class Component!</h1>
<input
value={this.state.value}
type="text"
onChange={this.onChange}
/>
<p>{this.state.value}</p>
</div>
);
}
}
위와 같이 클래스로 구현된 컴포넌트를 함수형 컴포넌트로 바꿀 수 있습니다.
const App = () => {
const [value, setValue] = useState('');
const onChange = e => setValue(e.target.value);
return (
<div>
<h1>This is function component!</h1>
<input value={value} type="text" onChange={onChange}/>
<p>{value}</p>
</div>
);
}
한 층 더 가벼워졌고 constructor를 더 이상 만들지 않아도 됩니다. 왜냐하면 Hook이 State를 초기화 해주고 다른 함수에서 제어할 수 있기 때문입니다. 만약 다음 컴포넌트에서 State를 관리해야 한다면 클래스 컴포넌트를 사용하는 것보다 함수형 컴포넌트를 사용하는 게 효율적입니다.
- `useEffect` Hook : 컴포넌트의 Side-Effect를 관리
import React from 'react';
const App = () => {
const [value, setValue] = React.useState('');
const onChange = event => setValue(event.target.value);
return (
<div>
<h1>Hello React with Local Storage!</h1>
<input value={value} type="text" onChange={onChange} />
<p>{value}</p>
</div>
);
};
export default App;
이제 State가 변할 때마다 컴포넌트는 업데이트 됩니다. state의 value는 브라우저의 local storage에 저장됩니다. 브라우저를 새로고침 할 때마다 애플리케이션이 재시작되고 컴포넌트의 생성자는 local storage로부터 state의 초기 상태를 가져옵니다.
이 컴포넌트는 local storage가 사용되기 때문에 render함수의 출력은 props에 대해 아는 것만으로는 예측할 수 없습니다. 왜냐하면 컴포넌트의 input(props)가 아닌 다른 곳에서 정보를 얻어서 side-effect가 발생하기 때문입니다.
이제 input field의 값을 local storage와 동기화하여 동일한 기능을 함수형 컴포넌트에 useEffect를 사용하여 구현해보겠습니다.
const App = () => {
const [value, setValue] = React.useState(
localStorage.getItem('myValueInLocalStorage') || '',
);
React.useEffect(() => {
localStorage.setItem('myValueInLocalStorage', value);
}, [value]);
const onChange = event => setValue(event.target.value);
return (
<div>
<h1>Hello React Function Component!</h1>
<input value={value} type="text" onChange={onChange} />
<p>{value}</p>
</div>
);
};
React의 useEffect Hook은 전달된 배열(두 번째 인수)의 값 중 하나가 변경될 때마다 실행됩니다. 위 코드의 경우 input field의 값이 변경될 때마다 local storage를 업데이트합니다. 또한 local storage의 값은 처음에 input field의 초기 값을 설정하는 데 사용됩니다.
함수형 컴포넌트는 state와 side-effect를 사용할 수 있기 때문에 본질적으로 훨씬 더 가볍습니다. 또한 local storage의 사용은 이전과 같이 다른 클래스의 함수로 사용되기 보다는 함수형 컴포넌트 안으로 이동했습니다.
다음 실행될 컴포넌트가 브라우저의 local storage에 호출하는 것과 같은 side-effect를 가져야 하는 경우에는 클래스 컴포넌트로 구현하기 보다는 Hooks가 포함된 함수 컴포넌트를 시도해보는 게 좋을 것 같습니다.
-
`custom` Hook : 추상화
지금까지 본 모든 Hook는 react에서 제공하는 내장된 hook들입니다. 그러나, hook을 새로운 사용자 정의 hook에 결합하는 것은 재사용이 가능한 컴포넌트 논리에 완벽히 들어맞습니다. 코드의 경우 local storage의 state와 side-effect에 대한 모든 논리를 사용자 정의 hook에서 추출할 수 있습니다.
const useStateWithLocalStorage = localStorageKey => {
const [value, setValue] = React.useState(
localStorage.getItem(localStorageKey) || '',
);
React.useEffect(() => {
localStorage.setItem(localStorageKey, value);
}, [value]);
return [value, setValue];
};
const App = () => {
const [value, setValue] = useStateWithLocalStorage(
'myValueInLocalStorage',
);
const onChange = event => setValue(event.target.value);
return (
<div>
<h1>Hello React Function Component!</h1>
<input value={value} type="text" onChange={onChange} />
<p>{value}</p>
</div>
);
};
`useStateWithLocalStorage` hook을 사용하면 state 관리를 할 수 있을 뿐만 아니라 브라우저의 local storage와 state를 동기화 할 수 있습니다. 구성요소가 마운트 될 때마다 local storage의 state가 사용됩니다. local storage는 처음에 저장한 값을 가지고 있습니다.
custom hook은 재사용 가능한 논리를 하나의 함수에 완벽하게 결합시켰습니다. 앞에서 본 클래스 컴포넌트에 모든 논리가 흩어져 있는 반면에 hook은 이 모든 조각을 모아서 캡슐화합니다. 상위 컴포넌트를 사용하여 동일한 추사화 계층을 추가하는 것이 가능했을 테지만, 그 논리는 여전히 상위 컴포넌트에 분산되어 있습니다.
※ 본 포스팅은 https://www.robinwieruch.de/react-hooks-migration/ 를 공부하며 번역한 글입니다.
'1st life_Programmer > React' 카테고리의 다른 글
[React] Binding 바인딩 (0) | 2019.07.26 |
---|
댓글