본문 바로가기

Frontend/React

[React] Hooks 기초 정리/가장 많이 쓰이는 hooks

728x90
반응형

React Hook 정의

React의 Hook은 16.8 버전부터 새로 추가된 기능이다. Hook은 함수형 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 “연동(hook into)“할 수 있게 해주는 함수라고 하고, Hook은 class 안에서는 동작하지 않으며, 대신 class 없이 React를 사용할 수 있게 해주는 것이다. 현재는 React Hook이 없다면 React 프레임워크를 사용하는 의미가 없을 정도로 매우 중요하다고 볼 수 있다.


React Hook 규칙

  • React Hook은 반복문, 조건문, 중첩된 함수내에서 호출하면 안됨. 이 규칙을 지키면 컴포넌트가 렌더링 될 때마다 항상 동일한 순서로 훅이 호출되는 것이 보장된다.
  • 일반적인 javascript 함수에서 호출하면 안됨 컴포넌트의 모든 상태 관련 로직을 소스코드에서 명확하게 보이도록 할 수 있다.
  • 이러한 React Hook의 규칙을 강제하도록 하는 ESLint 플러그인이 존재하는데 아래와 같이 패키지 매니저에 설치한다.
# npm
npm install eslint-plugin-react-hooks --save-dev
# yarn
yarn add eslint-plugin-react-hooks --dev

대표적으로 가장 많이 쓰는 React Hooks 5가지

1. useState

React Hooks 중에서도 가장 많이 쓰는 기본적인 상태 관리. 변수의 상태를 초기화하는 것에 있어서 useState 혹은 class의 constructor와 비슷한 포지션이라고 볼 수 있다. 다만 차이점은 class의 constructor는 한번만 호출되지만, useState는 여러번 호출이 가능하다는 점이다.

 

 

Using the State Hook – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

기본 문법 예시

import React, { useState } from 'react';

const Example = () => {
	// useState 선언, 상태 관리 초기값 설정
  const [count, setCount] = useState(0);

	// count의 값을 +1 해주는 함수
	const countUpBtnFn = () => {
    	setCount(count + 1);
	}

	// count의 값을 -1 해주는 함수
	const countDownBtnFn = () => {
    	setCount(count - 1);
	}

  return (
    <div>
    	<h1>{count}</h1>
        <p>버튼을 클릭해서 상태를 변경해보세요.</p>
      	<button onClick={countUpBtnFn}>증가</button>
        <button onClick={countDownBtnFn}>감소</button>
    </div>
  );
}

export default Example;

 

위 예시와 같이 React 패키지에서 useState 함수를 불러와 기본값 0으로 선언을 해준다. 그리고 button을 이전에 선언한 setCount를 통해서 count 값 상태를 변경 시킬 수 있다.

위 예시에는 useState 초기값을 0 즉, Int 타입으로 선언을 했지만 당연하게도 String(””), Object({}), Array([]), Boolean(true & false) 등 다른 다양한 타입으로도 선언이 가능하다.

여러개의 값을 넣는 예시

import React, { useState } from "react";

const InputExample = () => {
  const [inputs, setInputs] = useState({
    name: "",
    nickname: ""
  });

  const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출

  const onChange = (e) => {
    const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
    setInputs({
      ...inputs, // 기존의 input 객체를 복사
      [name]: value // name 키를 가진 값을 value 로 설정
    });
  };

  const onReset = () => {
    setInputs({
      name: "",
      nickname: ""
    });
  };

  return (
    <div>
      <input name="name" placeholder="이름 입력" onChange={onChange} value={name} />
      <input
        name="nickname"
        placeholder="닉네임 입력"
        onChange={onChange}
        value={nickname}
      />
      <button onClick={onReset}>초기화</button>
      <div>
        값: {name} ({nickname})
      </div>
    </div>
  );
}

export default InputExample;

 

처음 useState의 상태 초기값을 Object로 설정했으면 비구조화 할당을 통해서 useState에 있는 값을 추출하고 onChange 함수를 활용해 입력한 값에 따라 출력값 상태를 관리할 수 있다.

2. useEffect

DOM에서 렌더링 된 이후에 어떤 일을 수행해야 하는지를 명시할 때 사용하는 hook이다. useEffect 함수를 컴포넌트 함수 내에서 호출을 하게 되면 해당 함수내에 정의된 변수를 감지하는 것이 가능하며, 이로인해 useEffect 함수를 컴포넌트 함수 내에서 사용하는것이다.

 

useEffect는 화면이 렌더링 된 이후에 최초 한번 실행되고, 이후 상태가 변경될 때마다 계속 실행된다. React는 effect가 수행되는 시점에 이미 DOM이 업데이트되었음을 보장한다고한다.

useEffect 함수에 첫번째 인자로 전달하는 함수를 Effect하고 하고, 두번째 인자에 전달하는 값은 상태를 감지할 대상인 변수가 나열된 배열이며 해당 상태값들이 변경되었을 때만 effect가 실행되게 할 수도 있다. useEffect가 *컴포넌트에 마운트 될 때, 그리고 마운트가 해제 될 때만 호출되게 하고 싶다면 두번째 인자에 빈 배열을 넘겨주면 된다.

 

 

Using the Effect Hook – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

기본 문법 예시

// useEffect는 항상 useState와 함께 사용
import React, { useState, useEffect } from "react";

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

  useEffect(() => {
    console.log("Effect 실행됨");
    document.title = `카운트: ${count}`;
    // 컴포넌트가 처음 렌더링될 때와 count 상태가 변경될 때마다 실행되는 효과
    return () => {
      console.log("Clean up 함수 실행됨");
      // Effect가 언마운트 되거나, 다음 Effect가 실행되기 직전에 Clean up 함수가 실행됨
      document.title = "React Hooks Example";
    };
  }, [count]);

	// count의 값을 +1 해주는 함수
	const countUpBtnFn = () => {
		setCount(count + 1);
	}

  return (
    <div>
      <h1>{count}</h1>
      <p>버튼을 클릭해서 상태를 변경해보세요.</p>
      <button onClick={countUpBtnFn}>증가</button>
      <button onClick={countDownBtnFn}>감소</button>
    </div>
  );
};

export default Example;

 

위 예시에서는 useEffect를 사용하여 count 상태가 변경될 때마다 렌더링이 되고, document.title을 업데이트하는 효과를 추가하였다. 또한 clean up 함수를 활용하여 Effect가 언마운트 되거나 다음 Effect가 실행되기 직전에 정리 작업을 수행하도록 설정하였다.

clean up 함수는 useEffect에 대한 뒷정리를 해준다고 이해하면 된다.

3. useRef

js에서 특정 DOM을 선택할 때 getElementById, querySelect, querySelectAll 등을 사용하는데 반면, react에서도 ref를 사용해 특정 DOM을 선택해야할 때가 있다. useRef는 함수형 컴포넌트에서 ref를 사용할 수 있게 해주는 Hook으로, DOM 요소의 크기나 컴포넌트의 상태 등을 저장할 수 있다. 이 때, useRef를 사용 class형태는 React.createRef 형식을 사용한다.

 

 

Hooks API Reference – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

기본 문법 예시

import React, { useRef } from "react"; 

const refExample = () => {
  const nameInput = useRef(null);

  const handleBtnClick = () => {
		// input 요소에 접근하기 위해 useRef로 생성한 ref 객체 사용 
    nameInput.current.focus();
  };

  return (
    <div>
      <input ref={nameInput} type="text" />
      <button onClick={handleBtnClick}>입력창에 포커스 주기</button>
    </div>
  );
}

export default refExample;

4. useMemo

useMemo는 렌더링 성능을 최적화하기 위해 사용하는 Hook이며, 이전에 계산한 값을 재사용한다. 계산 비용이 큰 함수의 반환값을 기억하고, 해당 함수에 전달되는 인자가 변경되지 않으면 이전에 계산한 값을 반환한다.

 

 

Hooks API Reference – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

기본 문법 예제

import React, { useState, useMemo } from "react";

const memoExample = () => {
  const [count, setCount] = useState(0);

  // count의 제곱을 계산하는 함수
  const calculateSquare = useMemo(() => {
    console.log("계산됨");
    return count * count;
  }, [count]); // count가 변경될 때만 함수 재계산

  return (
    <div>
      <p>카운트: {count}</p>
      <p>카운트의 제곱: {calculateSquare}</p>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </div>
  );
};

export default memoExample;

 

위 예시는 count 상태의 제곱을 계산하는 컴포넌트를 구현했다. useMemo는 계산 비용이 큰 함수의 결과를 이전에 계산된 값으로 재사용할 수 있도록 도와주며, 두 번째 매개변수인 배열 [count]에 의해 count가 변경될 때만 함수가 재계산되고, 그렇지 않을 경우 이전에 계산된 값을 반환하여 성능을 최적화할 수 있다.

5. useCallback

useCallback은 useMemo와 비슷하게 동작하며, 함수를 캐싱하여 불필요한 렌더링을 방지해준다. 하지만, useMemo와 달리 생성된 함수를 반환한다. 또한 이전에 생성된 함수를 기억하고, 해당 함수에 전달되는 인자가 변경되지 않으면 이전에 생성한 함수를 반환한다.

 

 

Hooks API Reference – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

 

import React, { useState, useCallback } from "react";

const callbackExample = () => {
  const [count, setCount] = useState(0);

  // 카운트를 증가시키는 함수
  const handleIncrement = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []); // 컴포넌트가 처음 렌더링될 때만 함수 생성

  return (
    <div>
      <p>카운트: {count}</p>
      <button onClick={handleIncrement}>증가</button>
    </div>
  );
};

export default callbackExample;

 

count가 변경 될때마다 매번 고유한 함수가 생성된다. 그렇기 때문에 props가 변경됐다고 판단되어 매번 리렌더링이 발생하기 때문에 useCallback 함수를 사용하여 불필요한 리렌더링을 막을 수 있다.

Custom Hooks

React에 내장된 이러한 React Hook 함수들을 활용해 직접 필요한 hook을 만들 수 있다. custom hooks을 활용하면 중복되는 코드를 줄일 수 있고 이전 class형 React 컴포넌트에서는 불가능했던 로직 공유의 유연성을 제공한다.
즉, 미리 만들어뒀던 custom hook을 이용해 다른 컴포넌트에서도 언제든지 재사용이 가능하다.
아래는 Custom Hooks에 대한 공식 문서와 내가 봤던 정리 잘 되어있는 포스트이다.

 

 

자신만의 Hook 만들기 – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

 

 

21. 커스텀 Hooks 만들기 · GitBook

21. 커스텀 Hooks 만들기 이번에 사용 될 코드는 다음 CodeSandbox 에서 확인 할 수 있습니다. 컴포넌트를 만들다보면, 반복되는 로직이 자주 발생합니다. 예를 들어서 input 을 관리하는 코드는 관리 할

react.vlpt.us

 

728x90
반응형