React Hooks 란?
- 함수형 컴포넌트 ( function / 익명함수 const ??? = () => {} ) 에서도 상태 관리와 생명주기 메서드를 사용할 수 있게 해주는 기능
- React 16.8 버전부터 도입
- 간결한 코드 작성이 가능하게 도와준다.
주로 쓰이는 React Hooks
- useState : 컴포넌트의 상태(State) 를 선언하고 관리할 수 있다.
- React : useState란?
-
버튼 클릭 시 count 증가, 증가될 때 마다 Counter 컴포넌트 리렌더링.import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>현재 카운트: {count}</p> <button onClick={() => setCount(count + 1)}>증가</button> </div> ); }
-
- useEffect : 컴포넌트의 부수 효과(side effect)를 관리할 수 있다. (ex. 데이터 가져오기, DOM 업데이트 등)
- React : useEffect 란?
-
setInterval을 사용해 페이지가 마운트 된 후 지속적으로 숫자를 증가시켜 시간 표시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>; }
return 값으로 clearInterval를 줘서 페이지가 언마운트되면 interval을 정리함으로 데이터 누수 방지.
-
- useContext : React Context API 와 함께 사용되는 Hooks 이다.
부모 컴포넌트에서 하위 컴포넌트로의 데이터 전달을 Props 보다 간단하게 할 수 있다.
-
ThemeContext 는 현재 나의 Display 테마 데이터를 전달해주고 있고.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.Provider 에서의 value 값은 'dark' 로 전달중이기 때문에 현재 DisplayTheme 는 'Dark' 가 된다.
-
- useReducer : 복잡한 상태관리를 위해 useState의 대안으로 사용된다. (Redux와 유사한 패턴을 제공)
-
switch 문으로 case를 'increment' 와 'decrement' 로 나눠 증가,감소 를 나누고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> ); }
의도한대로 처리되지 않을 때를 대비해 default 로 에러를 발생시킨다.
-
- useRef : DOM 요소나 컴포넌트의 참조를 관리 (상태 변화 없이 데이터를 저장할 수도 있다.)
-
HTML 태그의 'name' 또는 'id'로 요소를 잡는것과 비슷하다고 생각할수도 있다.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> ); }
-
React Hooks 사용시 규칙
- Hooks 는 함수형 컴포넌트 안에서만 호출해야 한다.
-
함수 'notAComponent' 의 바깥에서 state 가 호출되었기 때문에 에러가 발생한다.import { useState } from 'react'; const [count, setCount] = useState(0); // 컴포넌트 외부에서 호출 function notAComponent() { return count; }
-
함수 'Counter' 내부에서 호출되었기 때문에 올바르게 상태관리를 할 수 있게됨.import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); // 컴포넌트 내부에서 호출 return <p>{count}</p>; }
p 태그 내의 count 값이 바뀔때마다 올바르게 리렌더링 될 것.
-
- Hooks 는 최상위 레벨에서만 호출해야 한다.
-
조건문 안쪽에서 호출 시, 리렌더링 될 때 마다 호출 순서가 달라질 수 있다.import React, { useState } from 'react'; function Counter({ shouldUseState }) { if (shouldUseState) { const [count, setCount] = useState(0); // if 조건문 안쪽에서 호출 } return null; }
이는 React 의 Hooks 호출 규칙을 깨트리기 때문에 오류를 유발함. -
조건문의 바깥, 'Counter' 함수의 최상위에서 호출한 뒤, return 문에서 삼항연산자로 count 값을 선언한다.import React, { useState } from 'react'; function Counter({ shouldUseState }) { const [count, setCount] = useState(0); // 컴포넌트의 최상위에서 호출 return shouldUseState ? <p>{count}</p> : null; }
이렇게 호출하면 호출 순서가 일정하게 유지된다.
-
Custom Hooks
- 반복해서 사용하는 로직을 추출하여 파일로 만들어놓고, 프로젝트 폴더 내에 Hooks 폴더를 만들어 관리할 수 있다.
- 사용하려는 컴포넌트에서 import 후, 최상위 레벨에서 호출하여 사용하면 된다.
- 사용 예시 (데이터 페칭과 관련된 예제)
-
useState 로 Data 와 loading 함수에 데이터와 로딩상태를 저장,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 }; // 데이터를 호출하는 컴포넌트에서 사용할 수 있도록 반환 }
useEffect를 사용해 url 값이 변경될때만 다시 실행되도록 최적화를 했다.
useFetch.jsx 를 만들어서 프로젝트의 Hooks 폴더에 저장한다.
이 파일을 App.jsx 에서 불러와 사용. -
따로 만들어놓은 useFetch 를 hooks 로 부터 import 해서 컴포넌트 내부에서 호출.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 에서 기능이 추가되거나 받아야 할 데이터가 늘어나는 등의 유지보수가 필요하다면
useFetch 파일만 수정하면 된다. (App 뿐만이 아닌, 여러 컴포넌트에서 사용중이라면)
-
'React' 카테고리의 다른 글
React : UseEffect (0) | 2024.12.28 |
---|---|
React : UseState (1) | 2024.12.26 |
React: 리액트란? (0) | 2024.12.24 |