React Hooks

안현희·2024년 11월 4일
2

React를 배워보자!

목록 보기
11/20

리액트 훅에 대해서 알아보자.

React Hooks

  • useState
  • useEffect
  • useRef
  • useContext
  • React.memo
  • useCallback
  • useMemo
  • 이전에 공부했던것들도 있지만 복습하는 차원에서 정리해보자.

1. useState

useStateReact에서 함수형 컴포넌트의 상태를 관리하기 위한 기본적인 Hook이다.

예시

import React, { useState } from 'react';

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

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}
  • useStatestate값이 변경될때마다 리렌더링된다.

2. useEffect

useEffect는 함수형 컴포넌트에서 부수 효과(side effects)를 처리하기 위해 사용된다. 데이터 가져오기, DOM 업데이트, 이벤트 구독/해제 등 부수 효과를 필요로 하는 작업을 처리할 때 유용하다.

예시

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

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(prevSeconds => prevSeconds + 1);
    }, 1000);

    return () => clearInterval(interval); // 컴포넌트가 언마운트될 때 정리(cleanup)
  }, []); // 빈 배열을 의존성으로 전달하여 마운트 시 한 번만 실행

  return <div>Seconds: {seconds}</div>;
}
  • 의존성 배열을 빈 배열로 전달하면 해당 부수 효과는 컴포넌트가 처음 마운트될 때 한 번만 실행된다.

  • 의존성 배열을 생략하면 컴포넌트가 리렌더링될 때마다 부수 효과가 실행된다.

  • 특정 상태나 값이 변경될 때만 부수 효과를 실행하려면 의존성 배열에 해당 상태를 추가하면 된다.


3. useRef

useRef는 함수형 컴포넌트에서 참조를 생성하는데 사용된다.

예시

import React, { useRef } from 'react';

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

  const focusInput = () => {
    inputRef.current.focus(); // input 요소에 직접 포커스를 설정
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}
  • useRefDOM요소에 접근할 뿐 아니라, 컴포넌트의 상태로 관리할 필요는 없지만 값이 리렌더링 간 유지되어야 할 때 사용된다.

  • 컴포넌트가 리렌더링될 때 useRef의 값은 유지되며, 이를 통해 값이 리셋되지 않도록 할 수 있다.


4. useContext

useContextReactContext API와 함께 사용되어, 컴포넌트 트리 전체에 걸쳐 전역 상태를 쉽게 공유할 수 있게 한다. props drilling피하고 싶을 때 유용하다.

예시

  • 먼저, Context를 생성하고, Provider를 통해 데이터를 공급한다.
import React, { createContext, useContext, useState } from 'react';

const ThemeContext = createContext();

function App() {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

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

function ThemeButton() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      Toggle Theme (Current: {theme})
    </button>
  );
}
  • props drilling을 피할때 사용하면 좋지만 리렌더링 성능에 영향을 줄 수 있으므로 필요한 경우에만 사용하고, 상태 분리 및 최적화가 필요할 수 있다.

5. React.memo, useCallback, useMemo

5-1. React.memo

React.memoprops가 변경되지 않으면 해당 컴포넌트를 다시 렌더링하지 않도록 해준다.

예시

import React from 'react';

const ChildComponent = React.memo(({ value }) => {
  console.log("ChildComponent rendered");
  return <div>{value}</div>;
});

function ParentComponent() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent value="Hello" />
    </div>
  );
}
  • 일반적으로는 리렌더링이 굳이 필요하지 않은 컴포넌트에 사용된다.
    이를 통해 불필요한 렌더링을 방지하여 성능을 최적화할 수 있다.

import "./TodoItem.css";
import { memo } from "react";

const TodoItem = ({ id, isDone, content, date, onUpdate, onDelete }) => {
  const onChangeCheckbox = () => {
    onUpdate(id);
  };

  const onClickDeleteBtn = () => {
    onDelete(id);
  };

  return (
    <div className="TodoItem">
      <input
        onChange={onChangeCheckbox}
        readOnly
        checked={isDone}
        type="checkbox"
      />
      <div className="content">{content}</div>
      <div className="date">{new Date(date).toLocaleDateString()}</div>
      <button onClick={onClickDeleteBtn}>제거</button>
    </div>
  );
};

export default memo(TodoItem);
  • React.memo는 위 예제와 같이 사용될 수도 있다.

5-2. useCallback

useCallback은 함수형 컴포넌트 내에서 함수를 메모이제이션하여, 함수가 불필요하게 다시 생성되지 않도록 하는 Hook이다.

예시

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

function ParentComponent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  const increment = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []); // 의존성이 없으므로 처음 생성된 함수를 재사용

  return (
    <div>
      <button onClick={increment}>Increment</button>
      <ChildComponent onClick={increment} />
    </div>
  );
}

const ChildComponent = React.memo(({ onClick }) => {
  console.log("ChildComponent rendered");
  return <button onClick={onClick}>Child Increment</button>;
});
  • useCallback을 사용하지 않으면, state가 변경될때마다 부모컴포넌트가 리렌더링되어 함수도 같이 재생성된다.

  • 하지만 위와 같이 useCallback을 사용하면
    함수가 메모이제이션이 되기 때문에 재생성되지 않는다.

React.memo와 useCallback을 함께 사용하는 이유

  • React.memoprops가 변경되지 않는 한 자식 컴포넌트를 리렌더링하지 않지만, 함수가 새로운 인스턴스로 생성되면 새로운 props로 간주되어 리렌더링이 발생할 수 있다.

  • 따라서, useCallback을 사용해 함수 인스턴스를 고정하면, 자식 컴포넌트가 불필요하게 리렌더링되지 않도록 할 수 있다.


5-3. useMemo

useMemo는 특정 계산 작업을 메모이제이션하여 불필요한 계산을 방지하는 Hook이다.

예시

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

function ExpensiveComponent({ number }) {
  const expensiveCalculation = (num) => {
    console.log("Calculating...");
    for (let i = 0; i < 1000000000; i++) {} // 오래 걸리는 작업
    return num * 2;
  };

  const result = useMemo(() => expensiveCalculation(number), [number]);

  return <div>Result: {result}</div>;
}

function App() {
  const [count, setCount] = useState(0);
  const [number, setNumber] = useState(1);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <button onClick={() => setNumber(number + 1)}>Increment Number</button>
      <ExpensiveComponent number={number} />
    </div>
  );
}
  • expensiveCalculation은 오래 걸리는 계산 작업을 수행하는 함수다.
    따라서, useMemo를 사용해 number가 변경될 때만 해당 계산을 실행하도록 설정했고, 이렇게 하면 count가 변경되어도 ExpensiveComponent가 재렌더링되더라도 expensiveCalculation함수는 다시 실행되지 않는다.

회고

  • 챌린지반 수업을 듣고나면 항상 멘탈이 갈린다.
    나만 그런줄 알았는데, 대부분의 수강생들이 그런것같아 다행이다.

  • 지금은 따라가느라 바쁘지만 나중에 뒤돌아봤을때
    맞아 그 땐 그랬지... 하며 기분좋게 회상 할 수 있다면 좋겠다.

  • 내일은 redux, react router dom, supabase에 대하여 공부해보자.

그럼이만

0개의 댓글