Light Blue Pointer
본문 바로가기
Developing/TIL(Develop)

[React] React Hook 리액트 훅

by Craft Fiend 2024. 9. 26.

어느날 갑자기 리액트를 하게 된 백엔드 개발자의 고군분투기...

회사 : 풀스택 해

 

React Hook이란?

리액트 훅(React Hooks)은 함수형 컴포넌트에서 상태(state)와 생명주기(lifecycle) 관련 기능을 사용할 수 있게 해주는 React의 기능이다.

리액트 훅이 등장하기 전에는 클래스형 컴포넌트만 상태 관리와 생명주기 기능을 사용할 수 있었으나, 훅 덕분에 함수형 컴포넌트에서도 이러한 기능을 쉽게 사용할 수 있게 되었다**useState**

  • 상태를 함수형 컴포넌트에서 관리하기 위한 훅입니다.
  • 초기 상태를 인자로 받고, 배열을 반환하며, 배열의 첫 번째 요소는 현재 상태 값, 두 번째 요소는 그 상태 값을 업데이트하는 함수
const [count, setCount] = useState(0);

function handleClick() {
  setCount(count + 1);
}

useEffect

  • 컴포넌트가 렌더링될 때와 렌더링 후에 수행할 작업(사이드 이펙트)을 정의하는 훅이다. 예를 들어, API 호출, 구독, 타이머 설정 등을 처리할 수 있습니다.
  • 기본적으로 useEffect는 컴포넌트가 마운트(처음 렌더링)될 때와 업데이트(리렌더링)될 때 실행됩니다.
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 'count'가 변경될 때마다 실행됨

갑작스럽게 React 세상에 내던져진 나는 useState 원툴로 살아가고 있었다…

그러나 세상에는 더 많은 React Hook들이 있었다

useContext

  • React의 Context API를 사용하여 컴포넌트 트리 전체에서 전역 상태를 쉽게 공유할 수 있도록 도와주는 훅
  • useContext를 사용하면 하위 컴포넌트들이 props를 통해 상태를 전달받지 않고도 직접적으로 필요한 상태에 접근할 수 있다
const value = useContext(MyContext);

useReducer

  • 복잡한 상태 로직을 관리할 때 사용된다
  • Redux와 유사하게, 상태 업데이트 로직을 컴포넌트 외부에서 정의하는 구조를 제공한다
  • useState가 관리하기에 너무 복잡한 상태일 경우 useReducer를 사용해 리듀서(reducer) 함수를 통해 상태를 관리한다
const [state, dispatch] = useReducer(reducer, initialState);

useRef

  • DOM 요소나 어떤 값이 변경되어도 리렌더링되지 않고 유지되어야 하는 값을 저장하는 데 사용된다
  • 보통 DOM 요소에 접근할 때 주로 사용되지만, 상태가 리렌더링에 영향을 미치지 않게 할 때도 활용된다
const inputRef = useRef(null);

function focusInput() {
  inputRef.current.focus(); // input에 포커스 설정
}

useMemo

  • 성능 최적화를 위해 계산된 값을 메모이제이션하는 훅
  • 컴포넌트가 렌더링될 때마다 비용이 많이 드는 계산을 방지하기 위해 특정 값이 변경될 때만 재계산되도록 할 수 있다.
const memoizedValue = useMemo(() => expensiveCalculation(a, b), [a, b]);

useCallback

  • 성능 최적화를 위해 함수의 메모이제이션을 제공하는 훅.
  • 함수가 필요할 때마다 새로 생성되지 않고, 의존성 배열에 명시된 값이 변경될 때만 새로 생성된다.
const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

훅의 특징

  1. 함수형 컴포넌트에서만 사용 가능: 훅은 클래스형 컴포넌트가 아닌 함수형 컴포넌트에서만 사용할 수 있다
  2. 상태와 생명주기 기능 제공: 기존에 클래스형 컴포넌트에서만 사용되던 상태와 생명주기 기능을 함수형 컴포넌트에서도 사용 가능하다
  3. 커스텀 훅: 개발자는 여러 훅을 조합해 자신의 커스텀 훅을 만들어 재사용 가능한 로직을 손쉽게 구현할 수 있다

1번도 모른채로 리액트 하라고 던져진 나는 리액트 개발 첫날에 리액트 훅의 존재를 직접 겪으면서 알게 되었다…

전역으로 상태를 저장했다가 다른 파일에서 사용해야 할 일이 있었는데 이렇게 했다가 에러를 마주하게 된다

const handleOnSubmit = async () => {
    const [dialog] = useDialogStore(state => [state.dialog]);
    const [session] = useChatStore(state => [state.session]);
    const dialogRequest = new  DialogRequest({
      test_case_id: dialog.name,
      name: dialog.name,
      description: dialog.description,
      cid: session.cid,
      author: dialog.author,
      call_key: session.callKey,
      result: dialog.result,
      dialogv1: JSON.stringify(dialog.dialogv1),
      dialogv2: ""
    });
    console.log(dialogRequest);
    const result = await sendDialog(dialogRequest);
    console.log(result);

    dialog.clearDialogV1();

    console.log("저장 버튼이 클릭되었습니다.");
  }

지금보니 정말 이상하지만 2주 전의 나는 정말 아무것도 몰랐다…

🚨문제

src\\components\\atoms\\SimpleDialog.tsx
  Line 46:22:  React Hook "useDialogStore" is called in function "handleOnSubmit" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use"  react-hooks/rules-of-hooks
  Line 47:23:  React Hook "useChatStore" is called in function "handleOnSubmit" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use"    react-hooks/rules-of-hooks

🔎원인

React Hook을 React 함수 컴포넌트 또는 사용자 정의 Hook 외에서 호출했기 때문에 생기는 에러

React 컴포넌트로 옮겨주고 해결해줄 수 있었다

const SimpleDialog = ({title, children, onClose, open, maxWidth = false, showSave = true}: Props) => {
  const [dialog] = useDialogStore(state => [state.dialog]);

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    handleClose(CloseType.SAVE);
  }