티스토리 뷰

개발../React

React Hooks 란?

링재호 2021. 9. 25. 23:08

React Hooks

React Hooks 는 React 16.8 버전에서 도입된 기능으로, 함수형 컴포넌트에서 상태 관리와 라이프사이클 메소드 등을 사용할 수 있게 해줍니다. 이전에는 클래스형 컴포넌트에서만 사용할 수 있었던 기능들을 함수형 컴포넌트에서도 사용할 수 있게 되면서 코드의 재사용성과 가독성이 증가하며, 컴포넌트의 성능도 최적화할 수 있습니다.

React Hooks 에서는 다음과 같은 기능들을 사용할 수 있습니다.

  • useState : 상태값을 관리하는 Hook
  • useEffect : 라이프사이클 메소드를 함수형 컴포넌트에서 사용할 수 있게 해주는 Hook
  • useRef : ref 를 사용할 수 있게 해주는 Hook
  • useContext : Context API 를 사용할 수 있게 해주는 Hook
  • useMemo : 컴포넌트 최적화에 사용되는 Hook 로, 연산된 값을 저장하여 재사용할 수 있게 해줍니다.
  • useCallback : 컴포넌트 성능을 최적화 시켜주는 Hook, 함수를 재사용하는 역할을 합니다.
  • useReducer
    • 상태 업데이트 로직을 컴포넌트에서 분리시켜 다른 파일에서 관리할 수 있게 해주는 Hook입니다.
    • state와 dispatch 라는 두 가지 값을 반환합니다.
    • state는 현재 상태값
    • dispatch는 상태를 업데이트하기 위한 함수를 의미합니다.
    • reducer 함수를 만들어서 사용합니다.
    • reducer 함수는 현재 상태와 액션 객체를 받아서 새로운 상태를 반환합니다.

Hooks 를 사용하면 클래스형 컴포넌트에서 사용되던 기능들을 함수형 컴포넌트에서도 사용할 수 있기 때문에, 코드의 재사용성과 가독성이 높아지며, 컴포넌트의 성능도 최적화할 수 있습니다.

useState

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

위 코드에서 useState 는 React Hook 중 하나입니다. 함수형 컴포넌트에서 상태값을 관리할 때 사용됩니다.

useState 는 배열 형태로 반환되며 첫 번째 원소는 현재 상태값, 두 번째 원소는 상태값을 변경하는 함수입니다. 이 함수는 인자로 변경될 값을 받습니다.

위 코드에서는 버튼을 클릭할 때마다 count 값을 1 증가시키고, 그 값을 화면에 렌더링합니다.

useEffect

import { useState, useEffect } from 'react';

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

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

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

위 코드에서는 useEffect 를 사용하여 컴포넌트가 업데이트될 때마다 document.title 을 업데이트하도록 설정하는 예제입니다. useEffect 는 함수형 컴포넌트에서 라이프사이클 메소드와 같은 역할을 하며, 컴포넌트가 마운트될 때, 언마운트될 때, 그리고 업데이트될 때 호출됩니다. 두 번째 인자로 전달된 배열은 useEffect 가 실행될 조건을 지정하는데, 해당 배열에 지정된 값이 변경될 때에만 useEffect 가 실행됩니다. 위 코드에서는 count 가 변경될 때마다 useEffect 가 실행되도록 설정되어 있습니다.

// 첫 발생 후, 컴포넌트가 렌더링 될 때마다 실행
useEffect(() => {
	// 작업
});

// 첫 발생 후, value 값이 바뀔 때 실행
useEffect(() => {
	// 작업
}, [value])

// clean up 으로 컴포넌트가 해지되거나 useEffect 가 해지될 때 해지시킨다.
useEffect(() => {
  // 작업 mount
	return () => {
		// 해지 unmount
	}
}, [])

useRef

state 와 동일하게 저장공간으로 사용, 하지만 아래와 같이 동작이 다름

state 변화⇒ 렌더링⇒ 컴포넌트 내부 변수들 초기화

ref 의 변화 ⇒ 노렌더링 ⇒변수들의 값이 유지됨

불필요한 렌더링을 막을 수 있음

Dom 요소에 접근(document.querySelector 와 비슷~)

import { useRef } from 'react';

function ExampleComponent() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
}

useContext

https://hong-jh.tistory.com/entry/Context-API는-왜-쓰고-그렇다면-Redux는-필요없을까

React Context API 를 이용하여 상태 관리를 할 수 있게 해주는 Hook 이다. Provider 로 설정한 값을 useContext 로 가져올 수 있다.

context api 는 props drilling 대신 사용하는데 유용하다. 즉 provider 내부에서 상태 변경이 거의 일어나지 않는다면, 해당 상태를 provider 하위의 다른 컴포넌트에 전달하는 용도로 쓰는데 적합하다.

그 예시로 주로 locale 이나 theme 정보 등을 언급한다.

주의점

Context 를 사용하면 컴포넌트를 재사용하기 어려워 질 수 있기 때문에 꼭 필요한 경우에만 사용하는 것이 좋다.

Prop drilling 을 피하기 위한 목적이라면 Component Composition (컴포넌트 합성)을 먼저 고려해보자

import React, { useContext } from 'react';
import { UserContext } from './UserContext';

function ExampleComponent() {
  const { user, setUser } = useContext(UserContext);
  // 사용할 값은 객체 구조 분해를 통해 작성 가능
  return (
    <div>
      <p>{user.name}</p>
      <button onClick={() => setUser({ name: 'New User' })}>Set User</button>
    </div>
  );
}

useMemo

컴포넌트 최적화에 사용되는 훅.

함수형 컴포넌트가 렌더링된다는 것은 컴포넌트 함수를 호출한다는 것이고 모든 내부 변수가 초기화됨. 이를 해결하기 위함.

useMemo(callback, dependceny array)

꼭 필요할 때만 사용 (값을 재사용하기 위해 따로 메모리를 사용해서 저장해두는 것. 그렇기 때문에 불필요한 값까지 모두 메모레제이션 하면 성능이 오히려 악영향이 올 수 있음.)

useMemo 는 컴포넌트 최적화에 사용되는 Hook 입니다.

함수형 컴포넌트가 렌더링된다는 것은 컴포넌트 함수를 호출한다는 것이고 모든 내부 변수가 초기화됩니다. 이를 해결하기 위해서 useMemo 를 사용합니다.

import { useState, useMemo } from "react";

const hardCalculate = (num) => {
  console.log("어려운 계산!");
  for (let i = 0; i < 10000000; i++) {}
  return num - 0 + 1000;
};

const easyCalculate = (num) => {
  console.log("쉬운 계산!");
  return num - 0 + 1;
};

function UseHookHandler() {
  const [hardNumber, setHardNumber] = useState(1);
  const [easyNumber, setEasyNumber] = useState(1);

  // hardNumber 가 변경되어야만 해당 로직을 재사용한다.
  const hardSum = useMemo(() => hardCalculate(hardNumber), [hardNumber]);
  const easySum = easyCalculate(easyNumber);

  return (
    <div>
      <h3>어려운 계산기</h3>
      <input
        type="number"
        value={hardNumber}
        onChange={(e) => setHardNumber(e.target.value)}
      />
      <span>+ 1000 = {hardSum}</span>

      <h3>쉬운 계산기</h3>
      <input
        type="number"
        value={easyNumber}
        onChange={(e) => setEasyNumber(e.target.value)}
      />
      <span>+ 1 = {easySum}</span>
    </div>
  );
}

export default UseHookHandler;

useMemo 의 첫번째 인자로 전달한 함수를 호출해서 반환되는 값을 메모이제이션합니다. 두번째 인자인 의존성 배열이 변경될 때만 함수가 호출되고, 그렇지 않으면 이전에 메모이제이션한 값을 재사용합니다.

꼭 필요할 때만 사용하세요. 값을 재사용하기 위해 따로 메모리를 사용해서 저장해두는 것이기 때문에 불필요한 값까지 모두 메모레제이션 하면 성능이 오히려 악영향을 줄 수 있습니다.

useCallback

import { useState, useCallback } from 'react';

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

  const handleIncrement = useCallback(() => {
    setCount(count + 1);
  }, [count]);

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

위 코드에서 useCallback 을 사용하여 함수를 재사용하도록 설정하는 예제입니다. useCallback 은 함수형 컴포넌트에서 성능 최적화를 위해 사용됩니다. 함수를 재사용하는 것은 함수를 반복해서 생성하지 않고, 이전에 생성된 함수를 재사용하게 되므로 메모리를 절약하고 컴포넌트의 렌더링 속도를 높일 수 있습니다.

위 코드에서는 handleIncrement 함수를 useCallback 을 사용하여 선언하고, count 의 값이 변경될 때마다 새로운 함수를 생성하지 않고 이전에 생성된 함수를 재사용하도록 설정되어 있습니다. 이렇게 하면 handleIncrement 함수가 여러 번 호출되더라도 함수를 반복해서 생성하지 않게 되므로 성능이 향상됩니다.

useReducer

import { useReducer } from 'react';

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

function reducer(state, action) {
  switch(action.type) {
    case INCREMENT:
      return {
        ...state,
        count: state.count + 1
      };
    case DECREMENT:
      return {
        ...state,
        count: state.count - 1
      };
    default:
      throw new Error();
  }
}

function ExampleComponent() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>You clicked {state.count} times</p>
      <button onClick={() => dispatch({ type: INCREMENT })}>+</button>
      <button onClick={() => dispatch({ type: DECREMENT })}>-</button>
    </div>
  );
}

위 코드는 useReducer 를 사용하여 간단한 카운터를 구현하는 예제입니다. useReducer 는 컴포넌트의 상태를 관리하는 Hook 중 하나로, useState 와 유사한 역할을 합니다. useReducer 는 현재 상태와 액션 객체를 전달받아 새로운 상태를 반환하는 리듀서 함수와 초기값을 인자로 받습니다.

reducer 함수는 현재 상태와 액션 객체를 전달받아 새로운 상태를 반환하는 함수입니다. 액션 객체는 type 필드를 가지고 있으며, 해당 필드를 기반으로 리듀서 함수에서 새로운 상태값을 계산합니다.

ExampleComponent 컴포넌트에서는 useReducer 를 사용하여 카운터 상태값을 관리하고, dispatch 함수를 사용하여 액션 객체를 전달합니다. dispatch 함수를 호출하면 리듀서 함수가 실행되어 새로운 상태값이 계산되며, 이를 통해 컴포넌트가 다시 렌더링됩니다.

'개발.. > React' 카테고리의 다른 글

React 생명주기 (lifecycle)  (0) 2022.01.25
Next.js  (0) 2021.11.15
Redux  (0) 2021.10.03
React-Router  (0) 2021.10.02
React  (0) 2021.09.11
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함