React는 v16.8부터 컴포넌트 상태와 컴포넌트 생명주기를 관리할 수 있는 API인 Hook을 제공한다. Hook을 사용하면 함수 컴포넌트도 클래스 컴포넌트처럼 컴포넌트 내부에 상태를 저장할 수 있고 컴포넌트 생명주기에 관여할 수 있다.
React Hooks는 기존 클래스 컴포넌트만 가지고 있던 여러 기능을 지원하기 때문에 함수 컴포넌트를 클래스 컴포넌트처럼 사용할 수 있다. 클래스 컴포넌트와는 다르게 함수 컴포넌트는 모듈화가 쉬워서 React 팀은 앞으로 컴포넌트를 제작할 때 함수 컴포넌트로 만들 것을 권장하고 있다.
Hooks의 장점은 로직의 재사용이 가능하고 관리가 쉽다는 것입니다. 함수 안에서 다른 함수를 호출하는 것으로 새로운 hook을 만들어 볼 수 있습니다.
기존의 class component는 여러 단계의 상속으로 인해 전반적으로 복잡성과 오류 가능성을 증가시켰습니다.
하지만, function component에 hooks에 도입되면서 class component가 가지고 있는 기능을 모두 사용할 수 있음은 물론이고 기존 class component 복잡성, 재사용성의 단점들까지 해결됩니다.
const [state, setState] = useState(initialState);
상태 유지 값과 그 값을 갱신하는 함수를 반환한다.
useState는 인자로 초기값을 받는다.
setState는 state 값을 갱신하고 싶을 때 사용하며, 새로운 state 값이 다음 렌더링 시에 최신 state 값으로 반영된다.
initialState 인자는 초기 렌더링 시에 사용하는 state 값이다.
setState 함수는 상태 업데이트를 비동기로 수행한다. 즉, 상태 업데이트를 나중으로 예약하고 현재 JavaScript 호출 스택이 전부 비워지면 그때 실제로 상태를 업데이트한다.
useEffect(() => fn(), []);
두번째 파라미터인 의존성 배열에 넘겨준 state가 변경된 경우에만 func 함수가 실행된다.
useEffect의 두번째 파라미터의 의미
Context란?
리액트 컴포넌트간에 어떠한 값을 공유할 수 있게 해주는 기능이다.
일반적으로 부모 컴포넌트에서 자식 컴포넌트로 props를 통해 데이터를 전달하는데, 만약 그 깊이가 깊어질수록 거쳐가야 하는 컴포넌트들이 많아지고 코드를 반복적으로 작성해야 하며 변수명이 바뀌면 거쳐가는 모든 컴포넌트에서 변수명을 수정해야 하는 등 꽤나 비효율적인 일들이 발생할 수 있다. (Props Drilling)
Context를 사용하면 전역적으로 데이터를 공유하기 때문에 중간 다리 역할만 하는 컴포넌트들을 건너뛰고, 데이터가 필요한 컴포넌트에서 필요한 데이터를 바로 사용할 수 있게 된다. 리액트 Hook인 useContext는 이러한 Context를 좀 더 편하게 사용할 수 있게 한다.
const MyContext = React.createContext(initialValue);
<MyContext.Provider value={123}>
<ChildComponent />
</MyContext.Provider>
useMemo
사용하기.const data = useContext(MyContext);
const reducer = (state, action) => {
switch (action.type) {
case "INIT":
return action.data; // return 값은 새로운 state가 된다.
case "CREATE": {
}
case "REMOVE": {
}
case "EDIT": {
}
default:
return state;
}
};
useReducer 사용법
const [state, dispatch] = useReducer(reducer, initialState);
dispatch 함수는 다음과 같이 사용한다.
dispatch({ type: "INIT", data: initData });
useMemo(() => fn, [])
반환
하게 된다.재사용
하는 Hook이다.컴포넌트가 렌더링 될 때마다 내부적으로 사용된 함수가 새롭게 생성되는 경우,
자식 컴포넌트에 Prop으로 새로 생성된 함수가 넘겨지게 되면 불필요한 리렌더링이 일어날 수 있다.
useMemo
와 useCallback
은 리렌더링을 최적화하는데 도움이 되도록 만들어진 Hook이다. 이 Hook들은 주어진 렌더에서 수행해야 하는 작업의 양을 줄이고, 컴포넌트가 다시 렌더링해야 하는 횟수를 줄이면서 리렌더링을 최적화하게 된다.리렌더링
이란, 이전에 생성한 컴포넌트 정보와 다시 렌더링할 정보를 비교해 최소한의 연산으로 DOM 트리를 업데이트 하는 것을 말한다. 즉, 이전의 Virtual DOM과 현재의 Virtual DOM을 비교하여 변경된 값에 대해 DOM 트리를 업데이트 해주는 것이다. React는 다음과 같은 조건에서 리렌더링을 진행한다.useMemo
는 특정 결과값을 재사용 할 때 사용하는 반면, useCallback
은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용다.useMemo
는 함수를 실행해서 실행 값을 반환하지만, useCallback
은 함수 자체를 반환하는 것이다.useMemo
는 함수의 연산량이 많을때 이전 결과값을 재사용하는 목적이고, useCallback
은 함수가 재생성 되는것을 방지하기 위한 목적이다.우리가 자바스크립트를 사용 할 때에는, 우리가 특정 DOM
을 선택하기 위해서 querySelector 등의 함수를 사용한다.
React를 사용하는 프로젝트에서도 가끔씩 DOM 을 직접 선택해야 하는 상황이 필요하다. 그럴때 우리는 useRef라는 React Hook을 사용한다.
컴포넌트나 HTML 엘리먼트를 레퍼런스로 관리할 수 있다.
useState
와 useRef
의 공통점은 함수형 컴포넌트에서 동적으로 상태 관리를 할 수 있게 해준다는 점이다. useState와 useRef 모두 주어진 state를 변화시킬 수 있다.
이 둘의 차이점은, useRef의 경우 state를 변화시키더라도 변화 후에 re-render가 되지 않아 화면이 렌더링되지 않는다.
반면, useState의 경우 선언한 state가 setter function에 의해 update될 경우, re-rendering process가 진행된다.
결과적으로, 각각의 state에서 이용할 hook을 설계할 때, 주로 state의 rendering 여부
를 바탕으로 결정하는 것이 좋다. Rendering이 필요한 state의 경우 useState를 이용하는 것이 간편하게 상태관리를 할 수 있으며, rendering이 필요하지 않은 state의 경우 useRef를 쓰는 것이 간단하게 코드를 작성할 수 있다.
App.js
import { useState, useRef } from "react";
function App() {
const [stateCount, setStateCount] = useState(0);
const refCount = useRef(0);
function upState() {
setStateCount(stateCount + 1);
}
function upRef() {
refCount.current += 1;
}
return (
<div>
<div>stateCount : {stateCount} </div>
<div>refCount : {refCount.current} </div>
<button onClick={upState}>state up</button>
<button onClick={upRef}>ref up</button>
</div>
);
}
export default App;
단순히 useCallback의 사용만으로는 하위 컴포넌트의 리렌더링을 방지할 수 없다.
컴포넌트가 React.memo()로 래핑 될 때, React는 컴포넌트를 렌더링하고 결과를 Memoizing 한다. 그리고 다음 렌더링이 일어날 때 props
가 같다면, React는 Memoizing 된 내용을 재사용한다.
React.memo
는 Higher-Order Components(HOC)
이고,
(HOC란 컴포넌트를 인자로 받아서 새로운 컴포넌트를 return해주는 구조의 함수)
useEffect
는 hook
이다.
참고문헌
https://react.vlpt.us/
https://medium.com/humanscape-tech/react-usestate-vs-useref-4c20713f7ef
https://velog.io/@hang_kem_0531/useMemo%EC%99%80-useCallback%EC%9D%98-%EC%B0%A8%EC%9D%B4