React Hooks

김형진·2024년 8월 23일
post-thumbnail

class없이 state를 사용할 수 있는 새로운 기능

Hook

함수형 컴포넌트에서도 React state와 생명 주기 기능을 연동 할 수 있게 해주는 기능

Hook을 사용하면 클래스형 컴포넌트 없이도 상태 관리, 사이드 이팩트 처리등을 할 수 있다.

1. useState

  • 컴포넌트의 상태를 관리하는 데 사용
  • 상태 변수와 그 값을 없데이트 하는 함수를 반환
import React, { useState } from "react";

const Component = () => {
  const [value, setValue] = useState(0);

  const upCount = () => {
    setValue(value + 1);
  };

  const downCount = () => {
    setValue(value - 1);
  };

  return (
    <div>
      <p>
        카운터 값 <b>{value}</b>
      </p>
      <button onClick={upCount}>+1</button>
      <button onClick={downCount}>-1</button>
    </div>
  );
};
export default Component;

버튼 클릭을 통해 state 값 변경하여 화면에 적용

2. useEffect

  • 컴포넌트가 렌더링 될때마다 특정 작업(side effect)을 실행할 수 있도록 하는 기능
  • 컴포넌트가 mount 될 때, unmount 될 때, update 할 때 특정 작업 처리 가능

출처: https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

사용 방법

useEffect(함수, deps)

함수: useEffect가 실행될때 작동할 작업, (return이 useEffect 내부에 있을 시 컴포넌트가 
Unmount 될때 혹은 업데이트 되기 직전 return 함수 실행)

deps: 배열 형태, 값이 있으면 마운트 할때와 지정 값이 업데이트 될때 useEffect 실행 
  1. 컴포넌트가 마운트 될 때 한번 실행
const Component = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log(`clicked ${count} times`);
  }, []);

  return (
    <div>
      <p>{count}번 클릭했습니다</p>
      <button onClick={() => setCount(count + 1)}>클릭</button>
    </div>
  );
};

deps값에 빈 배열을 입력하면 컴포넌트가 마운트 될 때 한 번만 실행한다

  1. 컴포넌트가 업데이트 될 때 실행
const Component = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log(`clicked ${count} times`);
  }, [count]);

  return (
    <div>
      <p>{count}번 클릭했습니다</p>
      <button onClick={() => setCount(count + 1)}>클릭</button>
    </div>
  );
};

count가 바뀔 때 마다 useEffect실행

  1. 컴포넌트가 업데이트 된 직후 실행하거나 언마운트 될때 실행 할 경우
const Component = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log(`clicked ${count} times`);
    return console.log(`total count ${count}`);
  }, []);

  return (
    <div>
      <p>{count}번 클릭했습니다</p>
      <button onClick={() => setCount(count + 1)}>클릭</button>
    </div>
  );
};

return 뒤에 오는 함수를 clean up 함수라고 한다. unmount 시 필요한 작업을 작성한다

의존성 변수가 있다면 useEffect가 다시 실행되기 전에 호출됩니다.

3. useMemo

  • 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술

  • 현재 종속성과 이전 종속성을 비교하여 종속성이 변경되었는지 확인합니다.

    • 종속성 변경 X ⇒ React는 함수를 다시 실행하지 않고 이전에 메모한 값을 반환
    • 종속성 변경 O ⇒ 함수를 실행하고 값을 새로 계산하고 메모 그다음, 이 메모 된 값을 반환
useMemo(함수, 의존성 배열)
const Component = () => {
  const [query, setQuery] = useState("");
  const [items] = useState([
    "Apple",
    "Banana",
    "Cherry",
    "Date",
    "Grape",
    "Orange",
  ]);
  const filteredItems = useMemo(() => {
    return items.filter((item) =>
      item.toLowerCase().includes(query.toLowerCase())
    );
  }, [query, items]);

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search items..."
      />
      <ul>
        {filteredItems.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
};

이 코드에서는 query와 items이 변경될 때만 필터링 된 리스트를 다시 계산한다.

의존성 배열이 변하지 않으면 useMemo는 이전 계산한 필터링 된 리스트를 반환한다.

4. useCallback

  • useMemo와 비슷하다 기능은 변수 대신 함수를 메모리에 저장해 두는 것이
const ChildComponent = ({ props }) => {
  console.log("ChildComponent rendered");
  return <button onClick={props}>Increment</button>;
};

const Component = () => {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("");

  const handleClick = useCallback(() => {
    setCount((prevCount) => prevCount + 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <ChildComponent props={handleClick} />
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Type something..."
      />
    </div>
  );
};

위 코드의 경우 handleClick함수가 부모 컴포넌트에서 자식 컴포넌트로 props로 전달된다.

이때 useCallback을 사용하지 않으면 부모 컴포넌트가 리랜더링 될 때,

handleClick함수가 새로 리랜더링 된다.

이 불필요한 리랜더링을 방지하기 위해 useCallback을 사용하여 함수를 미리 메모리에 저장해둔다

5. useRef

  • React에서 DOM 요소에 접근하거나, 재랜더링 간에 값이 변경되지 않는 변수를 유지하는 데 사용
const Component = () => {
  const [count, setCount] = useState(0);
  const countRef = useRef(0);

  useEffect(() => {
    countRef.current = count;
  }, [count]);

  const showAlert = () => {
    alert(`Latest count value: ${countRef.current}`);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={showAlert}>Show Alert</button>
    </div>
  );
};

이 코드에서는 useEffect가 cout가 변경 될 때마다 실행되고 변경된 count값을 countRef.current에 업데이트 한다. 이 때 변경된 countRef.current는 재랜더링되더라도 그 값을 유지한다.

6. custom Hook

  • 리액트는 제공해주지 않지만, 개발을 진행할 때 개인적으로 'hook'으로 만들면 더 편하겠다고 느낄 때, 자신만의 hook으로 만드는 것을 의미
  • use로 시작해야 함
  • state 자체가 아닌 state 저장 논리를 공유하는 것
  • custom hook은 순수 함수
  • 최상위에서만, React 함수 내에서만 호출해야 함
    • 반복문, 조건문, 중첩된 함수 내에서 Hook 호출 X
import { useState, useEffect } from "react";

const useWindowSize = () => {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    const handleResize = () => {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  return windowSize;
};

export default useWindowSize;
import React from "react";
import useWindowSize from "./useWindowSize";

const Component = () => {
  const { width, height } = useWindowSize();

  return (
    <div>
      <h1>Window Size</h1>
      <p>Width: {width}</p>
      <p>Height: {height}</p>
    </div>
  );
};

export default Component;

위 customhook을 통해 윈도우 크기 추적

useWindowSize란 훅을 제작 이 훅은 useState를 통해 windowSize를 반환한다.

useWindowSize훅에서는 useState로 윈도우의 크기를 측정하고 useEffect를 통해 변경되는

윈도우의 크기를 저장한다.

0개의 댓글