[React다루는기술] 10. React Hook


React Hook은 함수 컴포넌트에서 상태(state) 및 생명주기 기능을 사용할 수 있게 해주는 기능입니다. 훅은 함수 컴포넌트에서 상태 관리나 부수 효과(side effect) 등을 더 쉽게 다룰 수 있도록 도와줍니다. 리액트 훅은 함수형 컴포넌트에서만 사용할 수 있습니다.


1. useState

useState는 React에서 상태를 관리할 수 있게 해주는 훅(Hook) 중 하나입니다. 함수형 컴포넌트에서 상태를 사용할 수 있게 도와주며, 클래스 컴포넌트에서의 this.state와 유사한 기능을 제공합니다.

useState를 사용하려면 React에서 제공하는 useState 함수를 가져와야 합니다. 다음은 간단한 사용 예제입니다.

import React, { useState } from 'react';

function ExUseState() {
  // useState 훅을 사용하여 상태를 정의합니다.
  // count는 현재의 상태 값, setCount는 상태를 갱신하는 함수입니다.
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      {/* 버튼 클릭 시 setCount 함수를 사용하여 count 값을 갱신합니다. */}
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default ExUseState;



2. useEffect

useEffect는 React 함수형 컴포넌트에서 부수 효과(side effect)를 다루기 위한 훅(Hook) 중 하나입니다. 부수 효과란 컴포넌트 외부의 상태를 변경하거나, 데이터를 가져오는 등의 작업을 의미합니다. useEffect를 사용하면 컴포넌트의 렌더링 이후에 특정 작업을 수행할 수 있다.

useEffect는 두번째 파라미터 배열에 무엇을 넣는지에 따라 실행되는 조건이 달라진다. 컴포넌트가 언마운트되기 전이나 업데이트되기 직전에 어떠한 수행하고 싶다면 useEffect에서 cleanup함수를 반환해줘야 합니다.

import React, { useEffect } from 'react';

function ExUseEffect() {
  useEffect(() => {
    // 이곳에 부수 효과를 수행하는 코드를 작성합니다.
    console.log('Component is mounted!');

    // 컴포넌트가 언마운트되기 전에 정리(clean-up) 작업을 수행할 경우
    return () => {
      console.log('Component will unmount!');
      // 정리(clean-up) 코드 작성
    };
  }, []); // 두 번째 매개변수로 전달된 배열에 따라 언제 useEffect를 실행할지 결정됩니다.

  return (
    <div>
      <p>Component content goes here.</p>
    </div>
  );
}

export default ExUseEffect;

useEffect를 사용하면 컴포넌트 라이프사이클의 componentDidMount, componentDidUpdate, componentWillUnmount와 유사한 동작을 수행할 수 있습니다. 함수 컴포넌트에서 부수 효과를 다루는 데 유용하게 사용됩니다.


마운트 시에만 실행

useEffect(() => {
  console.log('Component is mounted!');
}, []);


특정 상태 값이 변경될 때만 실행

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

useEffect(() => {
  console.log('Count has changed:', count);
}, [count]);


마운트 및 언마운트 시에 실행 및 정리 작업

useEffect(() => {
  console.log('Component is mounted!');

  return () => {
    console.log('Component will unmount!');
    // 정리(clean-up) 코드 작성
  };
}, []);



3. useReducer

reducer는 현재 상태, 그리고 업데이트를 위해 필요한 정보를 담은 액션(action) 값을 전달받아 새로운 상태를 반환하는 함수이다. 새로운 상태를 주는 것은 불변성이다.

useReducer는 일반적으로 복잡한 상태 로직이나 여러 액션이 발생할 때 사용됩니다. 또한, useReducer는 useState로 대체 가능하지만, 코드를 더 구조적으로 유지하거나 상태 로직을 컴포넌트 외부로 분리할 때 유용하다.


import React, { useReducer } from 'react';

// reducer 함수
const reducer = (state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    default:
      return state;
  }
};

function Counter() {
  // useReducer 훅을 사용하여 상태와 dispatch 함수를 얻습니다.
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
    </div>
  );
}

export default Counter;


reducer 함수 :

  • reducer 함수는 현재 상태(state)와 액션(action)을 받아 새로운 상태를 반환하는 함수입니다.
  • 액션은 상태를 어떻게 업데이트할지에 대한 정보를 포함하고 있습니다.
  • reducer 함수는 switch 문이나 if-else 문을 사용하여 각 액션에 대한 업데이트 로직을 정의합니다.

dispatch 함수 :

  • dispatch 함수는 reducer 함수를 호출하여 상태를 업데이트하는 역할을 합니다.
  • 컴포넌트에서 dispatch 함수를 호출하면 reducer 함수가 실행되어 상태가 갱신됩니다.



4. useMemo

useMemo는 React의 훅 중 하나로, 계산 비용이 많이 드는 함수나 연산의 결과를 메모이제이션하여 성능을 최적화하는 데 사용됩니다. 특히 렌더링이 불필요하게 반복되는 경우에 유용하다.

useMemo Hook을 사용하면 list값이 변경되어야 만 getAverage 를 호출해서 평균을 계산한다.
그레서 input값이 변경된다고 계산하지 않는다.


import { useState, useMemo } from "react";

const getAverage = (numbers) => {
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const ExUseMemo = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState("");

  const onChange = (e) => {
    setNumber(e.target.value);
  };

  const onInsert = () => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  };

  //useMemo Hook을 사용하면 list값이 변경되어야 만 getAverage 를 호출해서 평균을 계산한다.
  //그레서 input값이 변경된다고 계산하지 않는다.
  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange} />
      <button onClick={onInsert}>등록</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <p>* 평균값:{avg}</p>
    </div>
  );
};

export default ExUseMemo; 



useCallback

useCallback의 의존성 배열에 여러 개의 값이 포함되어 있는 경우, 해당 값들 중 하나라도 변경되었을 때에만 함수가 다시 생성되고, 그렇지 않으면 메모이제이션된 함수가 재사용된다.

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

const ParentComponent = () => {
  const [countA, setCountA] = useState(0);
  const [countB, setCountB] = useState(0);

  // countA나 countB가 변경될 때에만 함수가 다시 생성
  const handleButtonClick = useCallback(() => {
    console.log('Button Clicked!');
    // 여기에 처리 로직 추가
  }, [countA, countB]);

  return (
    <div>
      <p>Count A: {countA}</p>
      <button onClick={() => setCountA(countA + 1)}>Increment A</button>

      <p>Count B: {countB}</p>
      <button onClick={() => setCountB(countB + 1)}>Increment B</button>

      <button onClick={handleButtonClick}>Handle Click</button>
    </div>
  );
};

const App = () => {
  return (
    <div>
      <ParentComponent />
    </div>
  );
};

export default App;



useRef

useRef는 React에서 참조(reference)를 다루는 훅 중 하나로, 주로 DOM 요소에 직접 접근하거나 함수 컴포넌트 내에서 변수를 유지하는 용도로 사용된다.

import React, { useRef, useEffect } from "react";

const ExUseRef = () => {
  const inputRef = useRef(null);

  useEffect(() => {
    // 마운트 시에 input 요소에 포커스를 주기 위해 useRef로 얻은 ref를 사용
    inputRef.current.focus();
  }, []);

  const handleButtonClick = () => {
    // 버튼 클릭 시 input 요소에 다시 포커스를 주기
    inputRef.current.focus();
  };

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

export default ExUseRef;