[React.js] HOOK

남현우·2022년 11월 27일
0

React

목록 보기
4/4
post-thumbnail

클래스형 컴포넌트

현재는 리액트에서 함수형 컴포넌트를 장려하고 대부분 클래스형 컴포넌트를 사용하지 않아,
클래스형 컴포넌트가 왜 존재하는지도 모르고 사용하는 경우가 생길 수 있다.
하지만, 클래스형 컴포넌트가 먼저 생겨났고, 문제점이 발생함에 따라 함수형으로 이를 극복하고자 했고,
그 과정에서 만들어진 훅이라는 멋진 기능이 태어났음을 안다면 리액트의 이해에 더 큰 도움이 될 수 있다.

먼저 아래의 클래스형 컴포넌트의 모습을 살짝 살펴보자.

import React, { Component } from 'react';
class TestComponent extends Component {
  state = {
    testState: "상태입니다."
  };
  render() {
    const { testProps } = this.props;
    const { testState } = this.state;
    return (
      <p>
        테스트 컴포넌트입니다.
        {testState}이건 테스트 상태이고,
        {testProps}이건 테스트 props입니다.
      </p>
    );
  }
}

export default TestComponent;

간단히 작성한 예시이기에 코드 내에서 props와 state의 방식이 다름만 알 수 있지만,
외에도 라이프사이클에 관련된 함수들을 사용할 수 있고 몇 차이가 있고 장점이 되는 것도 있다.

다만, 이런 차이점들에서 생겨난 문제점을 확인해보자.

  • 컴포넌트 사이에서 상태 로직을 재사용하기 어렵다.
  • 복잡한 컴포넌트들은 이해하기 어렵다.
  • 컴파일 단계에서 코드 최적화가 어렵다.
  • render함수가 필수적으로 필요해 마운트 속도가 느리다.
  • 선언이 보다 복잡하고, 메모리 자원을 많이 사용한다.

(리액트에서 공식적으로 발표한 동기는 링크를 통해 확인할 수 있다.)

함수형 컴포넌트

함수형 컴포넌트는 초기에 stateless component, 즉 상태가 없는 컴포넌트로 불리는 등 상태를 사용하지 못했었다.
하지만 이를 해결하며 클래스형 컴포넌트의 단점들을 함수형 컴포넌트로 극복하기 위해, 리액트는 Hook(훅)을 내놓게 되었다.

아래의 함수형 컴포넌트의 props사용과, useState훅을 사용한 상태 사용을 확인해보자.

import { useState } from 'react';
const TestComponent = ({testProps}) => {
  const [testState, setTestState] = useState();
  return (
    <p>
    	테스트 컴포넌트입니다.
        {testState}이건 테스트 상태입니다.
        {testProps}이건 테스트 props입니다.
    </p>
  );
}

대표적인 훅 useState를 사용해 코드를 작성한 예제로 props와 state의 사용이 확연히 다르다는 것을 알 수 있다.
외에도 앞서 언급한 문제점들을 대부분 극복하며 점점 더 많은 훅을 제공해 함수형 컴포넌트의 장점이 늘어나고 있다.

혹시 함수형 컴포넌트도 사용해보지 않아 모를 수 있는 사람을 위해 작성은 했지만, 알아볼 내용은 알아보았으니
훅은 어떤 것이 있는지 간략하게 알아보고, 커스텀 훅은 어떤 것인지 알아보려 한다.

Hook

useState

useState는 위에서도 확인한 훅으로, 함수형 컴포넌트에서 상태를 활용할 수 있게 해준다.

import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>버튼을 클릭하면 {count}가 증가합니다.</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

사용법은 위와 같이 사용할 상태의 이름과 상태를 바꿔줄 함수의 이름을 const [상태,함수]의 형태로 작성하고,
이어서 useState(초기값)의 형태로 작성한다.

useEffect

useEffect는 useState만큼 자주 활용되고 기초적인 훅으로, 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정 할 수 있다.

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

사용법은 위와 같이 useEffect() 내부에 컴포넌트가 변경되었을 때 실행할 내용을 작성한다.
위처럼 함수형으로 전달할 수 있지만, 아래와 같이 배열을 전달해 특정 값이 변경되었을 때 실행할지를 설정할 수 있다.
또, 마운트 될 때만 사용하고 싶다면 배열을 비운 채로 전달해 사용할 수 있다.

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  },[값 이름 배열]);

useContext

useContext는 context 객체를 받아 현재 값을 반환한다. (context는 전역 상태 핸들링을 가능하게 하며 자세한 정보는 링크에서 확인 가능하다.)
context의 현재 값은 트리 안에서 해당 훅을 호출하는 컴포넌트에 가장 가까이에 있는 <Context.Provider>의 value prop에 의해 결정된다.

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const TestContext = React.createContext(themes.light);

function App() {
  return (
    <TestContext.Provider value={themes.dark}>
      <Toolbar />
    </TestContext.Provider>
  );
}

function Toolbar(props) {
  return (
    <div>
      <Button />
    </div>
  );
}

function Button() {
  const theme = useContext(TestContext);
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      버튼의 스타일은 context를 통해 전달됩니다.
    </button>
  );
}

위는 리액트 공식 사이트에 있는 useContext의 예제이다.
Provider를 통해 감싸준 컴포넌트 안에서 useContext를 통해 쉽게 값을 전달받아 사용하는 방법을 알 수 있다.

추가 Hooks

위의 useState, useEffect, useContext외에도 다양한 훅이 존재한다.
useReducer, useCallback, useMemo, useRef등 계속해서 새로운 훅을 만들어 개발자의 개발을 편하게 돕고있다.
이러한 훅들을 활용해 리액트의 성능 최적화도 가능하며, 코드를 더 깔끔하게 만들 수도 있어 다양한 훅을 알아두면 유용하다.

Custom Hook

개발자는 존재하는 훅들을 이용해 자신만의 훅을 만들어낼 수 있다.
그저 use로 시작해 use뒤에 오는 첫 문자는 대문자여야 한다는 네이밍을 지켜 작성하면 되는데,
훅을 사용한 기능을 하나의 함수로 만들어둔다고 생각하면 어떤 것을 custom hook화 시켜야할지 생각하기 쉽다.

아래의 예시는 서버에서 데이터를 받아와 반환하는 내용의 커스텀 훅이다.

import { useState, useEffect } from 'react';

function useGetData(id) {
  const [data, setData] = useState(null);

  useEffect(() => {
    function handleStatusChange(data) {
      setData(data);
    }

    return () => {
      API.getDataFromServer(id, handleStatusChange);
    };
  });

  return data;
}

간단히 useEffect와 useState를 통해 만들었지만 이러한 내용이 컴포넌트 내에 들어갈 수록 코드가 복잡해진다.
따라서 로직을 구분하기 위해서는 커스텀 훅을 잘 활용하는 능력이 필요하다.


리액트를 처음 공부할 때, 함수형 컴포넌트만 사용하니 클래스형 컴포넌트를 공부할 생각은 하지 못하고
그게 리액트의 이해에 얼마나 큰 문제가 되는지를 몰랐었다.

하나의 기술의 과거부터 현재의 기술 진화를 알게되면 왜 그 기술이 나오게 되었고 어떤 의미를 가지며,
어떤 의도로 활용하는 것이 바람직한지를 파악할 수 있어 중요하다고 생각한다.

앞으로도 새로운 기술을 익혀도 가능하다면 그 기술의 과거도 학습할 수 있기를 바란다.

profile
개발 관련 지식을 기록하는 블로그입니다.

0개의 댓글