[React] React Hooks에 대하여(작성중)

82.831·2023년 1월 9일
0

React는 v16.8부터 컴포넌트 상태와 컴포넌트 생명주기를 관리할 수 있는 API인 Hook을 제공한다. Hook을 사용하면 함수 컴포넌트도 클래스 컴포넌트처럼 컴포넌트 내부에 상태를 저장할 수 있고 컴포넌트 생명주기에 관여할 수 있다.
React Hooks는 기존 클래스 컴포넌트만 가지고 있던 여러 기능을 지원하기 때문에 함수 컴포넌트를 클래스 컴포넌트처럼 사용할 수 있다. 클래스 컴포넌트와는 다르게 함수 컴포넌트는 모듈화가 쉬워서 React 팀은 앞으로 컴포넌트를 제작할 때 함수 컴포넌트로 만들 것을 권장하고 있다.

React Hooks의 장점

Hooks의 장점은 로직의 재사용이 가능하고 관리가 쉽다는 것입니다. 함수 안에서 다른 함수를 호출하는 것으로 새로운 hook을 만들어 볼 수 있습니다.
기존의 class component는 여러 단계의 상속으로 인해 전반적으로 복잡성과 오류 가능성을 증가시켰습니다.
하지만, function component에 hooks에 도입되면서 class component가 가지고 있는 기능을 모두 사용할 수 있음은 물론이고 기존 class component 복잡성, 재사용성의 단점들까지 해결됩니다.

기본 Hook

useState

const [state, setState] = useState(initialState);

상태 유지 값과 그 값을 갱신하는 함수를 반환한다.
useState는 인자로 초기값을 받는다.
setState는 state 값을 갱신하고 싶을 때 사용하며, 새로운 state 값이 다음 렌더링 시에 최신 state 값으로 반영된다.
initialState 인자는 초기 렌더링 시에 사용하는 state 값이다.
setState 함수는 상태 업데이트를 비동기로 수행한다. 즉, 상태 업데이트를 나중으로 예약하고 현재 JavaScript 호출 스택이 전부 비워지면 그때 실제로 상태를 업데이트한다.


useEffect

  • 컴포넌트가 렌더링될 때 특정 작업을 수행할 수 있도록 하는 Hook
useEffect(() => fn(), []);

두번째 파라미터인 의존성 배열에 넘겨준 state가 변경된 경우에만 func 함수가 실행된다.

useEffect의 두번째 파라미터의 의미

  1. 아무것도 전달하지 않음
    최초 렌더링 될 때와 그리고 그 후 어떤 state가 한번이라도 바뀔 때마다 첫번째 파라미터인 콜백함수가 실행된다.
  2. 빈 배열 []
    최초 렌더링 될 때, 한 번만 콜백함수가 실행된다.
  3. [state]
    최초 렌더링 될 때 한 번, 그리고 지정한 값이 바뀔 때 콜백 함수가 실행된다.

useContext

Context란?

리액트 컴포넌트간에 어떠한 값을 공유할 수 있게 해주는 기능이다.
일반적으로 부모 컴포넌트에서 자식 컴포넌트로 props를 통해 데이터를 전달하는데, 만약 그 깊이가 깊어질수록 거쳐가야 하는 컴포넌트들이 많아지고 코드를 반복적으로 작성해야 하며 변수명이 바뀌면 거쳐가는 모든 컴포넌트에서 변수명을 수정해야 하는 등 꽤나 비효율적인 일들이 발생할 수 있다. (Props Drilling)

Context를 사용하면 전역적으로 데이터를 공유하기 때문에 중간 다리 역할만 하는 컴포넌트들을 건너뛰고, 데이터가 필요한 컴포넌트에서 필요한 데이터를 바로 사용할 수 있게 된다. 리액트 Hook인 useContext는 이러한 Context를 좀 더 편하게 사용할 수 있게 한다.

Context API 3가지 주요 개념

  1. context 객체 생성
const MyContext = React.createContext(initialValue);
  • createContext 함수 호출 시 Provider와 Consumer 컴포넌트 반환
  • Provider를 사용하지않을 경우를 대비하여 initialValue 값을 넣어준다.
  1. Context 객체 안 Provider 컴포넌트
<MyContext.Provider value={123}>
	<ChildComponent />
</MyContext.Provider>
  • 컴포넌트간에 공유하고자 하는 값을 value라는 props로 설정하면 자식 컴포넌트들에서 해당 값에 바로 접근할 수 있다.
  • Provider에 제공한 value 값이 변경되면 useContext를 쓰고있던 모든 자식 컴포넌트가 리렌더링되기 때문에 주의해야한다. useMemo 사용하기.
  1. useContext
    ChildComponent에서 useContext라는 Hook을 사용해 value 값에 바로 접근 가능하다.
const data = useContext(MyContext);

추가 Hooks

useReducer

  • useState가 아닌 상태를 업데이트 하는 다른 방법
  • 상태 업데이트 로직을 reducer 함수에 따로 분리할 수 있다.

reducer란?

  • 현재 상태와 action 객체를 파라미터로 받아와 새로운 상태를 반환해주는 함수
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

useMemo(() => fn, [])
  • useMemo는 두번째 인자인 의존성 배열 deps에 변화가 생기면, 내부에 정의된 콜백 함수를 실행하고 그 함수의 반환 값을 반환하게 된다.
  • 의존성 배열에 적힌 값이 변할 때만 값을 다시 정의한다. 변하지 않을 경우 연산된 값을 재사용하는 Hook이다.

useCallback

  • deps의 변경을 통해 값이 변경이 되면 새로운 함수를 return하고, 값이 변경이 되어지지 않는다면 기존 함수를 return한다.

컴포넌트가 렌더링 될 때마다 내부적으로 사용된 함수가 새롭게 생성되는 경우,
자식 컴포넌트에 Prop으로 새로 생성된 함수가 넘겨지게 되면 불필요한 리렌더링이 일어날 수 있다.


useMemo와 useCallback의 공통점과 차이점

  • 기본적으로, useMemo와 useCallback리렌더링을 최적화하는데 도움이 되도록 만들어진 Hook이다. 이 Hook들은 주어진 렌더에서 수행해야 하는 작업의 양을 줄이고, 컴포넌트가 다시 렌더링해야 하는 횟수를 줄이면서 리렌더링을 최적화하게 된다.
    • 리렌더링이란, 이전에 생성한 컴포넌트 정보와 다시 렌더링할 정보를 비교해 최소한의 연산으로 DOM 트리를 업데이트 하는 것을 말한다. 즉, 이전의 Virtual DOM과 현재의 Virtual DOM을 비교하여 변경된 값에 대해 DOM 트리를 업데이트 해주는 것이다. React는 다음과 같은 조건에서 리렌더링을 진행한다.
      • 자신의 state가 변경될 때
      • 부모 컴포넌트로부터 전달받은 props가 변경될 때
      • 부모 컴포넌트가 리렌더링 될 때

  • useMemo는 특정 결과값을 재사용 할 때 사용하는 반면, useCallback은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용다.
  • useMemo는 함수를 실행해서 실행 을 반환하지만, useCallback은 함수 자체를 반환하는 것이다.
  • useMemo는 함수의 연산량이 많을때 이전 결과값재사용하는 목적이고, useCallback은 함수가 재생성 되는것을 방지하기 위한 목적이다.

useRef

우리가 자바스크립트를 사용 할 때에는, 우리가 특정 DOM 을 선택하기 위해서 querySelector 등의 함수를 사용한다.

React를 사용하는 프로젝트에서도 가끔씩 DOM 을 직접 선택해야 하는 상황이 필요하다. 그럴때 우리는 useRef라는 React Hook을 사용한다.

컴포넌트나 HTML 엘리먼트를 레퍼런스로 관리할 수 있다.


useState와 useRef의 공통점과 차이점

useStateuseRef의 공통점은 함수형 컴포넌트에서 동적으로 상태 관리를 할 수 있게 해준다는 점이다. 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;

React.memo와 useEffect의 차이점

단순히 useCallback의 사용만으로는 하위 컴포넌트의 리렌더링을 방지할 수 없다.

컴포넌트가 React.memo()로 래핑 될 때, React는 컴포넌트를 렌더링하고 결과를 Memoizing 한다. 그리고 다음 렌더링이 일어날 때 props가 같다면, React는 Memoizing 된 내용을 재사용한다.

React.memoHigher-Order Components(HOC)이고,
(HOC란 컴포넌트를 인자로 받아서 새로운 컴포넌트를 return해주는 구조의 함수)
useEffecthook이다.


참고문헌

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

0개의 댓글