React Hooks란 무엇일까?

React Hooks 이해하기


들어가며

React를 공부하고 이를 이용하여 프로젝트를 진행할 때, 꼭 빼놓을 수 없는 것이 React Hooks였던 것 같습니다. 이번 포스팅은 작업에 있어서 필수라고 느껴졌던 React Hooks의 등장 배경과 필요성 그리고 Class Component와 함수형 Component에 hooks를 적용하여 비교한 예시를 들어가며 간단하게 React Hooks를 이해하는 시간을 가져보도록 하겠습니다.




React Hooks란?

React Hooks의 등장 전,
Class Component VS 함수형 Component

React Hooks의 설명에 앞서 Class Component와 함수형 Component의 차이부터 이해하고 넘어가야 합니다. React Component는 Class형과 함수형(Funcional) 두 가지로 나뉠 수 있습니다. Class형은 함수형과 비교했을 때 코드가 더 길고 복잡하게 작성되며 이로 인해 더딘 성능을 보여주는 단점을 가지고 있습니다. Class를 사용해서 재사용 가능한 로직을 만들려면 HOC(High-Order-Component, 고차 컴포넌트)를 사용해서 만들어야 하는데 이렇게 사용하다 보면 많은 레이어들로 둘러싸인 HOC Hell을 겪게 되고 코드도 이해하기가 상당히 힘들어지기 때문입니다. 하지만 그럼에도 불구하고 React의 생명주기를 사용할 수 있었던 장점 때문에(함수형 Component가 더 간결하고 빠르더라도) Class Component를 써올 수밖에 없었다고 합니다.

React Hooks의 등장

위에서 언급한 Class Component 사용에서 느껴왔던 불편함이나 문제점들을 해결하기 위해 React Hooks가 등장하였고, React 16.8버전에 새로 추가된 기능으로 소개되었습니다.




React Hooks 왜 필요할까? (더 짧고 간결한 코드, 더 빠른 성능, 더 나은 가독성)

Hooks를 이용해서 어떤 부분이 긍정적으로 변화되었는지 코드를 비교하여 살펴보겠습니다.

  1. 함수형 Component에서도 생명주기를 사용할 수 있기에 데이터를 가져오고 Component를 시작하자마자 API를 호출하는 기능을 활용할 수 있게 되었습니다.

Class Component

import React, { Component } from 'react';
import Axios from 'axios';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = { name: '' };
  }

  componentDidMount() {
    Axios.get('/api/user/name').then((response) => {
      this.setState({ name: response.data.name });
    });
  }

  render() {
    return <div>My name is {this.state.name}</div>;
  }
}

함수형 Component, React Hooks

import React, {useEffect, useState} from "react"
import Axios from "axios"

export default function App() {

  const [Name, setName] = useState("")

  useEffect(() => {
    Axios.get('/api/user/name')
    .then(response => {
        setName(response.data.name)
      })
  }, [])

  render() {
    return (
      <div>
        My name is {Name}
      </div>
    )
  }

}


  1. Class Component에서 생명주기를 이용할 때와 함수형 Component에서 React Hooks을 사용할 때 더욱 선명하게 간결해진 코드를 비교하여 보겠습니다. Class Component에서는 componentDidMount, componentDidUpdate, componentWillUnmount로 다르게 처리해 주지만 React Hooks을 이용하면 useEffects 안에서 모두 처리할 수 있습니다.

Class Component: 생명주기 이용

componentDidMount() {
  // Component가 Mount 되면 updateLists 함수를 호출
  this.updateLists(this.props.id)
}
componentDidUpdate() {
  if(prevProps.id !== this.props.id) {
    // updateLists 함수를 호출할 때 사용되는 id가 달라지면 다시 호출
    this.updateLists(this.props.id)
  }
}
// updateLists 함수 정의
updateLists = (id) => {
  fetchLists(id)
  .then((lists) => this.setState({
    lists
  }))
}

함수형 Component: React Hooks를 이용하여 생명주기 이용

useEffects(() => {
  fetchLists(id).then((repos) => {
    setRepos(repos);
  });
}, [id]); // id값이 바뀌었을때 재실행


  1. HOC Component를 활용해서 많은 Wrapper Component로 감싸지게 되는 경우 복잡해지는 코드를 Custom React Hooks로 대체해서 가독성 있고 간단하게 줄일 수 있습니다.
    ( HOC, High-Order-Component란? 화면에서 재사용 가능한 로직만을 분리해서 Component로 만들고, 다른 부분들은 parameter로 받아서 처리하는 방법입니다. 이 방법의 단점은 너무나 많은 Wrapper Component가 생길 수 있다는 점입니다. 아래의 예시처럼 Wrapper가 너무 많아지면 데이터 흐름을 파악하기 힘들어집니다. React Hooks에서는 Custom Hooks를 이용해서 Component를 만들어 처리해줍니다. 이로 인해 Wrapper가 많아지는 일을 방지할 수 있으며 코드가 간결하고 가독성있게 정리될 수 있습니다. )

Class Component: 반복되게 사용되는 로직을 HOC(High order component)로 활용한 예시

const HocHell = () => {
  return (
    <Hoc>
      <positionHOC>
        <sizeHOC>
          <themeHOC>
            <TestComponent />
          </themeHOC>
        </sizeHOC>
      </positionHOC>
    </Hoc>
  );
};

함수형 Component: Hooks을 사용해서 TestComponent를 render 한 예시

const WithHooks = () => {
  const position = usePosition()
  const size = useSize()
  const theme = useTheme()

  return (
    <TestComponent
      position={position}
      size={size}
      theme={theme}
    >
  )
}



마치며

위의 예시들로 React Hooks가 무엇인지, 어떠한 장점을 가지고 있는지 간단하게 알아보았습니다. 하지만 React Hooks를 제대로 알기 위해서는 위의 내용 말고도 공부해야 하는 내용이 굉장히 많습니다. 특히 React에서 지원하는 Hooks의 API의 종류를 이해하고 적용해 보는 것이 필요합니다. 아래의 참고 링크를 보시면 Hooks API Reference의 정보를 확인하실 수 있으니 다양한 예시를 찾아보며 공부해 보시면 많은 도움이 될 것 같습니다 :)

참고문서


    추천 글