본문 바로가기

프로그래밍/React

리액트(React) - Hooks 알아보기

리액트를 공부하면서 쓰는 글이니 오류가 있을 수 있습니다. 있다면 알려주시면 감사하겠습니다!

 

Hooks

리액트의 Hooks는 클래스형 컴포넌트에서 사용하는 상태 관리와 생명주기 메서드를 이용하는 기능을 함수형 컴포넌트에서 사용할 수 있게 해주는 함수입니다.  hooks에는 여러 가지 hook이 존재합니다. 이번 글에서 어떤 것이 있는지 알아봅니다.

 

Hooks - useState()

useState는 함수형 컴포넌트에서 상태 관리를 할 수 있는 hook입니다. useState를 이용하면 상태를 관리하는 변수와 함수를 반환합니다.

import React, { useState } from "react";

const Counter = () => {
    const [count, setCount] = useState(0);
    return (
        <div>
            <div>지금 숫자는:{count}</div>
            <button onClick={() => {setCount(count + 1);}}>추가</button>
        </div>
    );
};

export default Counter;

useState를 사용하여 반환받은 setCount를 사용하면 다시 렌더링이 발생합니다. 여러 개의 state를 변경하려면 여러 개의 useState를 사용하여 변경합니다.

Hooks - useEffect()

useEffect는 클래스형 컴포넌트에 있는 생명주기 메서드인 componentDidMount(), componentDidUpdate(), componentWillUnmount() 메서드를 합쳐둔 hook입니다.

import React, { useEffect, useState } from "react";

const Counter = () => {
    const [count, setCount] = useState(0);

    const btnClick = () => {
        console.log("추가");
        setCount(count + 1);
    }

    useEffect(() => {
        console.log("렌더링이 끝났어요!");
    });

    return (
        <div>
            <div>지금 숫자는:{count}</div>
            <button onClick={btnClick}>추가</button>
        </div>
    );
};

export default Counter;

해당 코드를 실행하면 디버그 콘솔에 추가가 먼저 나타난 후 렌더링이 끝났다고 나오는 것을 볼 수 있습니다. 따라서 렌더링이 끝나고 필요한 작업을 진행하면 됩니다.

 

useEffect를 컴포넌트가 마운트되었을 때만 사용하고 싶다면 useEffect의 두 번째 인수를 빈 배열로 넘겨주면 됩니다.

useEffect(() => {
    console.log("렌더링이 끝났어요!");
},[]);

이렇게 빈 배열을 넣어 실행하면 클릭 했을때 리 렌더링이 되어도 렌더링이 끝났다는 말이 나타나지 않습니다.

 

또한 원하는 변수가 변경될때만 실행이 되게 할 수 있습니다.

useEffect(() => {
    console.log("렌더링이 끝났어요!");
},[count]);

이렇게 변경하면 count 상태 변수가 변경될 때만 실행됩니다.

 

이번에는 useEffect를 사용하여 마운트가 해제될 때 실행되는 코드를 알아봅니다.

useEffect는 언마운트가 되어야 할 때 실행되려면 함수를 반환해야 합니다. 리액트에서는 이것을 clean-up이라고 합니다.

말 그대로 모든 작업이 끝나고 정리가 필요한 상황에 쓰입니다. 

import React, { useEffect, useState } from "react";

const Counter = () => {
    const [count, setCount] = useState(0);

    const btnClick = () => {
        console.log("추가");
        setCount(count + 1);
    }

    useEffect(() => {
        console.log("렌더링이 끝났어요!");
        return () => {
            console.log("사라져요..");
        }
    });

    return (
        <div>
            <div>지금 숫자는:{count}</div>
            <button onClick={btnClick}>추가</button>
        </div>
    );
};

export default Counter;

코드를 실행하고 추가 버튼을 한 번씩 누르면 콘솔에 "추가" 다음 "사라져요."가 먼저 나타나고 마지막에 "렌더링이 끝났어요"가 나타납니다. 

 

이렇게 되는 이유는 useEffect가 렌더링이 실행될 때마다 실행이 되기 때문입니다. 물론 컴포넌트가 언마운트 될 때도 실행이 됩니다.

useEffect가 실행되면 그전에 있던 useEffect에서 반환한 정리 함수를 먼저 실행하고 새로 실행된 useEffect가 진행됩니다.

 

정리 함수를 언마운트가 될 때만 실행하고 싶다면 빈 배열만 두 번째 인수에 넣으면 됩니다.

Hooks - useReducer()

useReducer는 useState를 대체할 수 있는 메서드입니다. useReducer는 상태를 관리하는 복잡한 코드를 따로 함수로 빼서 사용할 수 있고 새로 변경할 state가 이전의 state값에 의존적일 때 useReducer를 선호한다고 합니다.

 

상태 관리를 할 함수를 만들고 useReducer에 만든 함수와 초기 state를 전달해주면 됩니다. 상태 관리할 함수는 state와 action을 인자로 가지고 있어야 합니다. 그 후 useState처럼 만들어진 함수를 호출하여 상태를 변경합니다.

import React, { useReducer } from "react";

function CountUpdate(state, action) {
    switch (action.type){
        case "up":
            return {count: state.count + 1};
        case "down":
            return {count: state.count - 1};
        default:
            return state;
    }
}

const Counter = () => {
    const [state, dispath] = useReducer(CountUpdate,{count:0});

    return (
        <div>
            <div>지금 숫자는:{state.count}</div>
            <button onClick={() => { dispath({type:"up"}); }}>업</button>
            <button onClick={() => { dispath({type:"down"}); }}>다운</button>
        </div>
    );
};

export default Counter;

dispath를 호출하여 atction값을 넘겨주면 만들어두었던 함수가 호출되며 상태가 변경이 됩니다. dispatch에는 type이 들어있는 객체로 넘겨주면 되며 type의 값은 문자열이나 숫자가 들어가도 상관없습니다.

 

Hooks - useMemo()

useMemo는 메모이제이션(Memoization)이라는 기술을 사용합니다. 메모이제이션은 연산을 진행할 때 결과를 저장해 두고 중복된 연산이 있을 경우 저장된 결과를 사용하여 처리속도를 빠르게 하는 기술입니다.

 

useMemo를 이용해서 렌더링을 빠르게 할 수 있습니다.

Hooks - useCallback()

useCallback은 useMemo와 비슷하게 메모이제이션을 사용합니다. 같은 함수를 새로 생성하지 않고 생성된 함수를 재사용합니다.

useCallback에 인수로 함수와 배열을 넘겨줍니다. 배열은 넘겨진 값이 바뀌었을 때만 호출되도록 합니다.

배열에 값을 넘겨줄 때 함수에서 상태 값을 사용한다면 배열에 함수에서 사용하는 상태 값을 넘겨주어야 합니다. 

 

Hooks - useRef()

함수형 컴포넌트에서 ref를 사용할 수 있게 해주는 hook입니다. 클래스형 컴포넌트에서 createRef처럼 사용합니다. 

import React, { useRef, useState } from "react";

const RefTest = () => {
    const [state, setState] = useState("숨기기");
    const domRef = useRef();

    const onHideShow = () => {
        if(domRef.current.hidden) {
            domRef.current.hidden = false;
            setState("숨기기");
        }
        else {
            domRef.current.hidden = true;
            setState("보이기");
        }
    }

    return (
        <div>
            <div ref={domRef}>헤헤</div>
            <button onClick={onHideShow}>{state}</button>
        </div>
    )
}

export default RefTest;

ref객체에 접근하려면 current 프로퍼티를 먼저 접근해야 합니다.

 

useRef는 DOM 객체를 조작할 때 사용할 수도 있지만 컴포넌트에서 사용할 변수로도 사용이 가능합니다.

인수로 초기값을 넣어주면 초기값으로 초기화된 ref객체를 반환합니다. useRef는 리렌더링이 되지 않으니 렌더링과 관련되지 않은 값을 관리할 때 사용해야 합니다.

 

사용자 정의 Hook

사용자 정의 hook은 use로 시작하는 함수이며 컴포넌트에서 처리하는 같은 코드가 있을 때 따로 하나의 함수로 만들어 사용하는 것입니다. 

 

참고

리액트를 다루는 기술(개정판) - 김민준 지음

https://ko.reactjs.org/docs/hooks-overview.html