Class06(hook)
2022. 09. 01. , 09. 06. 수업내용 정리
Hook .. 개요, 장단점..
-
소개
- React 16.8 버전 (2019년도) 에 추가된 공식 라이브러리.
- Class 형 컴포넌트에서만 쓸 수 있었던 state와 life cycle을 Function형 컴포넌트에서도 사용 가능.
- 현재 공식문에서는, Class형 컴포넌트보다는 Function형 컴포넌트로 새로운 React 프로젝트를 만들기를 권장.
- 단, 기존의 Class형 컴포넌트들을 Hook을 이용한 Function형 컴포넌트로 refactoring할 이유는 전혀 없음.
-
사용이유
-
클래스형 컴포넌트들은 method의 개념이므로, 리렌더링디 되더라도 render()를 제외한 나머지 method, state는 그대로 보존되어 있으나
함수형 컴포넌트들은 리렌더링이 될 시, 함수 안에 작성된 모든 코드가 다시 실행됩니다.
- 기존에 가지고 있던 상태(state)를 전혀 관리(기억)할 수 없게 만듭니다. 이는 리렌더링 시 무조건 새롭게 선언 & 초기화 & 메모리에 할당이 된다는 의미입니다. (메모리 자원을 사용하기에 함부로 남발하면 오히려 성능저하를 불러올 수 있음)
- Hook에서 브라우저에 메모리를 할당 함으로서, 함수형 컴포년트가 상태(state)를 가질 수 있게 한 것입니다.
- 그 밖에도 컴포넌트 사이에서 상태 로직 재사용의 어려움(render props, HOC 등)
- 복잡한 (클래스형) 컴포넌트들은 이해하기 어려움 (각종 생명주기 함수들)
- 클래스 자체 개념의 어려움(this)
-
-
규칙
-
Hook에는 규칙이 있다. 이를 꼭 지켜야 정상적으로 hook이 실행되고 코드가 꼬이지 않습니다.
- 최상위에서만 Hook을 호출
- React 함수(컴포넌트)의 최상위에서만 Hook을 호출 할 것.
- 반복문, 조건문, 중첩된 함수등에서 호출 X
- React 함수에서만 Hook을 호출
- Custom Hook에서는 호출 가능
- 일반적인 Javascript 함수에서는 호출 X
- Hook을 만들 때 앞에 use 붙이기
- 그래야만 한눈에 보아도 Hook 규칙이 적용되는지를 파악할 수 있기 때문 (공홈)
- 그래야만 한눈에 보아도 Hook 규칙이 적용되는지를 파악할 수 있기 때문 (공홈)
- React는 Hook 호출되는 순서에 의존
- 한 컴포넌트에서 여러개의 hook이 사용되는 경우
- hook은 위에서부터 아래로 순서에 맞게 동작한다.
function Form() { // 1. name이라는 state 변수를 사용하세요. const [name, setName] = useState('Mary'); // 2. Effect를 사용해 폼 데이터를 저장하세요. useEffect(function persistForm() { localStorage.setItem('formData', name); }); // 3. surname이라는 state 변수를 사용하세요. const [surname, setSurname] = useState('Poppins'); // 4. Effect를 사용해서 제목을 업데이트합니다. useEffect(function updateTitle() { document.title = name + ' ' + surname; }); // ... }
- Hook에 호출 순서에 따른 결과
// ------------ // 첫 번째 렌더링 // ------------ useState('Mary') // 1. 'Mary'라는 name state 변수를 선언합니다. useEffect(persistForm) // 2. 폼 데이터를 저장하기 위한 effect를 추가합니다. useState('Poppins') // 3. 'Poppins'라는 surname state 변수를 선언합니다. useEffect(updateTitle) // 4. 제목을 업데이트하기 위한 effect를 추가합니다. // ------------- // 두 번째 렌더링 // ------------- useState('Mary') // 1. name state 변수를 읽습니다.(인자는 무시됩니다) useEffect(persistForm) // 2. 폼 데이터를 저장하기 위한 effect가 대체됩니다. useState('Poppins') // 3. surname state 변수를 읽습니다.(인자는 무시됩니다) useEffect(updateTitle) // 4. 제목을 업데이트하기 위한 effect가 대체됩니다. // ...
- 최상위에서만 Hook을 호출
-
-
Hook의 최적화를 위해 신경써야할 요소
- 컴포넌트가 반드시 필요한 리랜더링만을 진행하는가?
- 랜더링이 발생한다면, property 및 method가 반드시 필요한 것만 재할당 할 수 있게 하는가?
- 위 2가지를 무시할만큼, 랜더링이 자주되는가? ) 따라서 메모리를 할당하면서 위의 2가지를 지키지 않아도 되는가?
-
장점
-
함수형 컴포넌트로 코드 통일 가능
-이전에는 state 유무로 클래스형과 함수형을 판별.
-
useEffect로 클래스형 Lifecycle에 흩어져 있는 로직 묶음
-클래스형 컴포넌트에서 로직을 재사용하기 위해 썼던 HOC나 render-props 같은 패턴이 가져오는 컴포넌트 트리의 불필요한 중첩을 없애줌.
// class componentDidMount() { this.updateList(this.props.id); } componentDidUpdate(prevProps) { if (prevProps.id !== this.props.id) { this.updateList(this.props.id); } } updateList = () => { feachList(id).then((list) => this.setState({list})); } // hooks useEffect(() => { feachList(id).then((res) => setRes(res)); }, [id]); 출처: https://developerntraveler.tistory.com/146 [개발여행의 블로그:티스토리]
-
-
단점
-
호출되는 순서에 의존
-
hooks는 반복문, 조건문, 중첩된 함수 내에서 호출이 불가합니다.
-
예를 들어 클릭하면 페이징되는 버튼을 구현하기 위해 useFetch를 사용하려고 한다면, react-async-hook 라이브러리를 사용하거나 custom hook을 만들어 해결해야 합니다.
-
hooks의 규칙을 따르기 위해 많은 리소스가 필요하고, 코드가 많아지면 복잡성이 증가합니다.
-
-
useEffect의 빈틈
-
useEffect는 두번째 인수로 dependency list를 받고, 하나의 값이라도 변경됐을 때 useEffect 내부의 로직을 실행하여 라이프 사이클을 흉내냅니다.
-
React에서 hooks’ dependency array의 변경을 감지하기 위해 Object.js()메서드를 사용하는데, 대체로 원시 타입에 올바르게 작동합니다.
-
참조형 데이터를 비교할 때는 렌더링 될 때 마다 참조 메모리 주소가 다르기 때문에 매번 실행됩니다.
-
useMemo를 사용하여 동일한 객체가 전달될 수 있도록 처리할 수 있지만, 개발자가 놓치고 넘어가기 쉬운 포인트인 것 같습니다.
-
-
Hooks는 클로저에 의존적이다.
- 프로그램이 커질수록 Hooks가 많아지는데, 클로저는 복잡성을 증가시킨다. 최신상태가 아닌 클로저는 해결하기 어렵습니다.
function WatchCount() { const [count, setCount] = useState(0); useEffect(function() { setInterval(function log(){ console.log(`Count is: ${count}`); }, 2000); }, []); return ( <div> {count} <button onClick={()=>setCount(count+1)}> Increase </button> </div> ); }
위 코드에서 출력된 count는 항상 0이다. console.log()는 생성될 때의 count(0)을 캡처하여 기억하고 있으므로, 계속 count는 0일 것입니다.
해결하기 위해 하단과 변경할 수 있지만, 클로저 역시 예상하기 어렵습니다.function WatchCount() { const [count, setCount] = useState(0); useEffect(function() { setInterval(function log(){ console.log(`Count is: ${count}`); }, 2000); return function() { clearInterval(id); }; [count] ); return ( <div> {count} <button onClick={()=>setCount(count+1)}> Increase </button> </div> ); }
- 프로그램이 커질수록 Hooks가 많아지는데, 클로저는 복잡성을 증가시킨다. 최신상태가 아닌 클로저는 해결하기 어렵습니다.
-
-
Hook 종류
자체적으로 제공하는 기본 Hook, 추가 Hook이 있고 사용자가 만들어서 사용할 수 있는 Custom Hook이 있습니다.
-
기본 Hooks
- useState (동적 상태 관리)
- useEffect (side effect 수행 -mount/unmount/update)
- useContext (컴포넌트를 중첩하지 않고도 전역 값 쉽게 관리)
-
추가 Hooks
- useReducer (복잡한 컴포넌트들의 state를 관리 -분리)
- useCallback (특정 함수 재사용)
- useMemo (연산한 값 재사용)
- useRef (DOM선택, 컴포넌트 안에서 조회/수정할 수 있는 변수 관리)
- useImperativeHandle
- useLayoutEffect
- useDebugValue
ref)리액트 Hook 장단점
ref)Hook의 개요
-
댓글남기기