React

React : React Hooks

종구 2024. 12. 28. 19:51
React Hooks 란?
  • 함수형 컴포넌트 ( function / 익명함수 const ??? = () => {} ) 에서도 상태 관리와 생명주기 메서드를 사용할 수 있게 해주는 기능
  • React 16.8 버전부터 도입
  • 간결한 코드 작성이 가능하게 도와준다.

 

주로 쓰이는 React Hooks
  • useState : 컴포넌트의 상태(State) 를 선언하고 관리할 수 있다.
  • React : useState란?
    • import React, { useState } from 'react';
      
      function Counter() {
        const [count, setCount] = useState(0);
      
        return (
          <div>
            <p>현재 카운트: {count}</p>
            <button onClick={() => setCount(count + 1)}>증가</button>
          </div>
        );
      }
      버튼 클릭 시 count 증가, 증가될 때 마다 Counter 컴포넌트 리렌더링.
  • useEffect : 컴포넌트의 부수 효과(side effect)를 관리할 수 있다. (ex. 데이터 가져오기, DOM 업데이트 등)
  • React : useEffect 란? 
    • import React, { useState, useEffect } from 'react';
      
      function Timer() {
        const [seconds, setSeconds] = useState(0);
      
        useEffect(() => {
          const interval = setInterval(() => setSeconds((s) => s + 1), 1000);
          return () => clearInterval(interval); // 정리(cleanup)
        }, []);
      
        return <p>경과 시간: {seconds}초</p>;
      }
      setInterval을 사용해 페이지가 마운트 된 후 지속적으로 숫자를 증가시켜 시간 표시
      return 값으로 clearInterval를 줘서 페이지가 언마운트되면 interval을 정리함으로 데이터 누수 방지.
  • useContext : React Context API 와 함께 사용되는 Hooks 이다.
    부모 컴포넌트에서 하위 컴포넌트로의 데이터 전달을 Props 보다 간단하게 할 수 있다.
    • import React, { createContext, useContext } from 'react';
      
      // 1. Context 생성
      const ThemeContext = createContext('light');
      
      function ThemeDisplay() {
        // 2. Context 값 소비
        const theme = useContext(ThemeContext);
        return <p>현재 테마: {theme}</p>;
      }
      
      function App() {
        return (
          // 3. Context 값 제공
          <ThemeContext.Provider value="dark">
            <ThemeDisplay />
          </ThemeContext.Provider>
        );
      }
      
      export default App;​
      ThemeContext 는 현재 나의 Display 테마 데이터를 전달해주고 있고.
      ThemeContext.Provider 에서의 value 값은 'dark' 로 전달중이기 때문에 현재 DisplayTheme 는 'Dark' 가 된다.
  • useReducer : 복잡한 상태관리를 위해 useState의 대안으로 사용된다. (Redux와 유사한 패턴을 제공)
    • import React, { useReducer } from 'react';
      
      function reducer(state, action) {
        switch (action.type) {
          case 'increment':
            return { count: state.count + 1 };
          case 'decrement':
            return { count: state.count - 1 };
          default:
            throw new Error();
        }
      }
      
      function Counter() {
        const [state, dispatch] = useReducer(reducer, { count: 0 });
      
        return (
          <div>
            <p>Count: {state.count}</p>
            <button onClick={() => dispatch({ type: 'increment' })}>+</button>
            <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
          </div>
        );
      }
       switch 문으로 case를 'increment' 와 'decrement' 로 나눠 증가,감소 를 나누고
      의도한대로 처리되지 않을 때를 대비해 default 로 에러를 발생시킨다.                                                                 
  • useRef : DOM 요소나 컴포넌트의 참조를 관리 (상태 변화 없이 데이터를 저장할 수도 있다.)
    • import React, { useRef } from 'react';
      
      function FocusInput() {
        const inputRef = useRef();
      
        const focusInput = () => {
          inputRef.current.focus();
        };
      
        return (
          <div>
            <input ref={inputRef} type="text" />
            <button onClick={focusInput}>포커스 주기</button>
          </div>
        );
      }
      HTML 태그의 'name' 또는 'id'로 요소를 잡는것과 비슷하다고 생각할수도 있다.
React Hooks 사용시 규칙
  • Hooks 는 함수형 컴포넌트 안에서만 호출해야 한다.
    • import { useState } from 'react';
      
      const [count, setCount] = useState(0); // 컴포넌트 외부에서 호출
      
      function notAComponent() {
        return count;
      }​
      함수 'notAComponent' 의 바깥에서 state 가 호출되었기 때문에 에러가 발생한다.
    • import React, { useState } from 'react';
      
      function Counter() {
        const [count, setCount] = useState(0); // 컴포넌트 내부에서 호출
        return <p>{count}</p>;
      }
      함수 'Counter' 내부에서 호출되었기 때문에 올바르게 상태관리를 할 수 있게됨.
      p  태그 내의 count 값이 바뀔때마다 올바르게 리렌더링 될 것.

  • Hooks 는 최상위 레벨에서만 호출해야 한다.
    • import React, { useState } from 'react';
      
      function Counter({ shouldUseState }) {
        if (shouldUseState) {
          const [count, setCount] = useState(0); // if 조건문 안쪽에서 호출
        }
        return null;
      }
      조건문 안쪽에서 호출 시, 리렌더링 될 때 마다 호출 순서가 달라질 수 있다. 
      이는 React 의 Hooks 호출 규칙을 깨트리기 때문에 오류를 유발함.
    • import React, { useState } from 'react';
      
      function Counter({ shouldUseState }) {
        const [count, setCount] = useState(0); // 컴포넌트의 최상위에서 호출
        return shouldUseState ? <p>{count}</p> : null;
      }
      조건문의 바깥, 'Counter' 함수의 최상위에서 호출한 뒤, return 문에서 삼항연산자로 count 값을 선언한다.
      이렇게 호출하면 호출 순서가 일정하게 유지된다.

Custom Hooks
  • 반복해서 사용하는 로직을 추출하여 파일로 만들어놓고, 프로젝트 폴더 내에 Hooks 폴더를 만들어 관리할 수 있다.
  • 사용하려는 컴포넌트에서 import 후, 최상위 레벨에서 호출하여 사용하면 된다.
  • 사용 예시 (데이터 페칭과 관련된 예제)
    • import { useState, useEffect } from 'react';
      
      function useFetch(url) {
        const [data, setData] = useState(null); // 데이터를 저장할 상태
        const [loading, setLoading] = useState(true); // 로딩 상태를 관리
      
        useEffect(() => {
          fetch(url)
            .then((response) => response.json()) // 응답을 JSON으로 변환
            .then((result) => {
              setData(result); // 데이터를 상태에 저장
              setLoading(false); // 로딩 완료로 상태 업데이트
            });
        }, [url]); // URL이 변경될 때마다 실행
      
        return { data, loading }; // 데이터를 호출하는 컴포넌트에서 사용할 수 있도록 반환
      }
      useState 로 Data 와 loading 함수에 데이터와 로딩상태를 저장, 
      useEffect를 사용해 url 값이 변경될때만 다시 실행되도록 최적화를 했다.
      useFetch.jsx 를 만들어서 프로젝트의 Hooks 폴더에 저장한다.
      이 파일을 App.jsx 에서 불러와 사용.
    • import React from 'react';
      import useFetch from './hooks/useFetch'; // hooks 폴더의 useFetch.jsx를 import
      
      function App() {
        const { data, loading } = useFetch('https://api.example.com/data');
        // useFetch 에서 선언한 data 와 loading 을 App 내부에서 호출한다.
      
        return <div>{loading ? '로딩 중...' : JSON.stringify(data)}</div>;
        // 삼항연산자를 사용. 
        // useFetch의 괄호 안에 정의된 주소에서 데이터를 전부 가져오기 전엔 true 반환으로 '로딩 중...' 표시
        // 데이터를 전부 가져오면 true 반환으로 가져온 데이터를 찍어준다.
      }
      
      export default App;
       따로 만들어놓은 useFetch 를 hooks 로 부터 import 해서 컴포넌트 내부에서 호출.
      만약 useFetch 에서 기능이 추가되거나 받아야 할 데이터가 늘어나는 등의 유지보수가 필요하다면
      useFetch 파일만 수정하면 된다. (App 뿐만이 아닌, 여러 컴포넌트에서 사용중이라면)

'React' 카테고리의 다른 글

React : UseEffect  (0) 2024.12.28
React : UseState  (1) 2024.12.26
React: 리액트란?  (0) 2024.12.24