[TIL] React Hooks

ShallWeDance·2021년 8월 3일
1

React

목록 보기
5/6
post-thumbnail

등장배경

React는 버전 16.8 이전까지 Class 바탕의 코드로 구성되어 있었습니다. 하지만 아래의 여러가지 문제점이 발생하게 되었습니다.

  • 컴포넌트 사이에서 상태를 재사용하기 어렵습니다.
    React는 기본적으로 재사용 가능하게 상태로직을 붙이는 방법을 제공하지 않았습니다.(그래서 상태관리 라이브러리인 Redux나 mobX 등등을 사용할 수 밖에 없었습니다) 그래서 render props나 고차 컴포넌트와 같은 패턴을 사용함으로서 이러한 문제를 해결하기 위해 노력했습니다. 너무 복잡하죠.

  • 복잡한 컴포넌트들을 이해하기 어렵습니다.
    React는 코드의 길이가 길어질수록 직관적으로 이해하기 특히나 어려웠습니다. 그 예로 lifecyle method의 componentDidMountcomponentDidUpdate는 컴포넌트 안에서 데이터를 가져오는 작업을 수행할 때 사용되지만, 같은 componentDidMount에서 이벤트 리스너를 설정하는 것과 같은 관계없는 로직이 포함되기도 하며, componentWillUnmount에서 cleanup 로직을 수행하기도 합니다.

  • Class는 this 키워드와 사용하기 복잡합니다.
    JavaScript의 this가 어떻게 작동하는지를 알아야지 React에서 Class를 사용할 수 있습니다. 그러나, 다른 언어와는 다르게 JavaScript는 this가 다르게 동작함으로서(이 부분은 저도 공부가 필요합니다) 혼동을 주게 되었고 어렵게 만들었습니다.


Hook 사용 규칙

  • 최상위(at the top level)에서만 Hook을 호출해야 합니다.
  • React 함수 컴포넌트 내에서만 Hook을 호출해야 합니다. 일반 JavaScript 함수에서는 Hook을 호출해서는 안 됩니다.

장점

  • 로직의 재사용이 가능하고 관리가 쉽다.
    • 함수형 컴포넌트이므로 함수안에서 다른 함수를 호출하는 것으로 새로운 Hook을 만들 수 있다.
    • 따라서 원하는 기능들을 쉽게 조립해서 custom Hook을 만들 수 있다.
  • 로직을 한 곳으로 모을 수 있어서 가독성이 좋다.
    • 클래스형 컴포넌트의 라이프사이클 API는 서로 다른 로직이 하나의 메서드에 섞여 있어서 가독성이 좋지 않다. Hook은 같은 로직을 한 곳으로 모을 수 있다
  • 상태 관리 방법을 Class 보다 더 쉽게 설명할 수 있다.

Hooks API

기본 Hooks

useState

상태를 유지하는 값과 그 값을 갱신하는 함수를 반환합니다.
const [state, setState] = useState(initialState);

setState 함수는 state를 갱신할 때 사용합니다.
setState(newState);

간단한 카운터 함수를 만들어 보겠습니다.

import React, { useState } from 'react';
// 카운터 함수
const Counter() => { 
  const [count, setCount] = useState(0);
  return (
  <>
    Count: {count};
    <button onClick={() => setCount(0)}>Reset</button>
    <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
    <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
  </>
  );
};

총 세개의 버튼을 리턴하는 함수입니다. 초기값은 0으로 되어있고 0이 initialState가 됩니다.
"+" 버튼을 누르면 1씩 증가하고, "-" 버튼을 누르면 1씩 감소할 수 있도록 계산합니다. "Reset" 버튼을 누르면 초기값인 0으로 바뀔 수 있도록 상태를 바꿔주고 있습니다.

useEffect

useEffect 는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정 할 수 있는 Hook 입니다. 함수 컴포넌트에서 side effect를 수행할 수 있습니다. componentDidMountcomponentDidUpdate 등 lifecyle method 들을 합친 형태로 봐도 무방합니다.

//기본 형태
useEffect(()=>{
  console.log('기본입니다.');
});
// 처음 렌더링 될때만 실행(마운트 될 때)
useEffect(()=>{
  console.log('마운트 될 때만 실행됩니다.');
},[]);
// 특정 값이 업데이트 될 때만 실행
useEffect(() => {
  console.log('setState 값이 업데이트 될 때마다 실행됩니다.');
},[setState]);
// 특정 값은 여러개 넣을 수 있습니다.
useEffect(() => {
  console.log('여러개의 값이 업데이트 될 때마다 실행됩니다.');
},[setState, setCount]);

side effect들을 내가 원하는대로 관리할 수 있기 때문에 잘 사용한다면 여러가지 활용이 가능합니다.

useContext

useContext는 react 자체적으로 global한 상태를 공유하기 위해서 만들어졌습니다. context 객체(React.createContext에서 반환된 값)을 받아 그 context의 현재 값을 반환합니다.
const value = useContext(MyContext);


추가된 Hooks

추가된 Hooks들은 특정한 경우에만 사용됩니다. 기본 Hooks를 익힌 뒤 알아도 충분합니다.

useReducer

useState의 대체 함수입니다. 현재의 상태와 업데이트를 위해 필요한 정보를 담은 액션값을 전달 받아 새로운 상태를 반환하는 함수입니다. 리듀서와 마찬가지로 새로운 상태를 만들 때는 꼭 불변성을 지켜야합니다.

const [state, dispatch] = useReducer(reducer, initialArg, init);

Redux 에서는 액션 객체에는 어떤 액션인지 알려주는 type 필드가 꼭 있어야 하지만, useReducer 에서 사용하는 액션 객체는 꼭 type 를 지니고 있을 필요가 없습니다. 심지어, 객체가 아니라 문자열이나, 숫자여도 상관이 없습니다.

useCallback

메모이제이션된 콜백을 반환합니다. 다음에 나오는 useMemo와 상당히 비슷한 함수입니다. 주로 렌더링 성능을 최적화해야 하는 상황에서 사용하며, 이 Hook을 사용하면 이벤트 핸들러 함수를 필요할 때만 생성 할 수 있습니다.

const onChange = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

onChange와 같은 이벤트 핸들러 함수들을 선언하게 되면 컴포넌트가 리렌더링 될 때마다 이 함수들이 새로 생성됩니다. 대부분의 경우에는 이러한 방식이 문제가 되지 않지만, 컴포넌트의 렌더링이 자주 발생하거나, 렌더링 해야 할 컴포넌트의 개수가 많아진다면 이 부분을 최적화 해주시는 것이 좋습니다.

useMemo

메모이제이션된 값을 반환합니다.

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

useMemo 를 사용하면 함수형 컴포넌트 내부에서 발생하는 연산을 최적화 할 수 있습니다.

❗️❗️useCallback과 useMemo의 차이

useCallback 은 결국 useMemo 에서 함수를 반환하는 상황에서 더 편하게 사용 할 수 있는 Hook 입니다. 숫자, 문자열, 객체 처럼 일반 값을 재사용하기 위해서는 useMemo 를, 그리고 함수를 재사용 하기 위해서는 useCallback 을 사용하면 됩니다.

useRef

useRef Hook 은 함수형 컴포넌트에서 ref 를 쉽게 사용 할 수 있게 해줍니다.

const refContainer = useRef(initialValue);

useRef는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환합니다. 본질적으로 useRef는 .current 프로퍼티에 변경 가능한 값을 담고 있는 “box”와 같습니다.
DOM에 접근하기 위해서 ref를 사용하기보다 useRef가 순수 자바스크립트 객체를 생성하기 때문에 useRef를 사용하는 것이 더 유용합니다.
하지만 이렇게 넣는 ref 안의 값은 바뀌어도 컴포넌트가 렌더링 되지 않기 때문에 렌더링과 관련되지 않은 값을 관리 할 때만 사용하는 것이 좋습니다.

Reference

React 공식사이트
리액트의 Hooks 완벽 정복하기

0개의 댓글

관련 채용 정보