본문 바로가기
1st life_Programmer/React

[React] Hooks : 클래스 컴포넌트에서 함수형 컴포넌트로

by Z선배 2019. 7. 25.

리액트팀에서 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

댓글