React Hooks

YeJI Kang·2021년 9월 9일
0
post-thumbnail

본 포스팅은 '실무에서 알아야할 기술은 따로 있다! 리액트를 다루는 기술'을 보고 정리한 글입니다.

Hooks?

Hook는 리액트 v16.8부터 함수형 컴포넌트에서도 상태 관리를 할 수 있는 기능을 제공합니다.

useState

reference code

useState는 컴포넌트에서 상태를 관리할 때 기본적으로 사용하는 Hook입니다.

  1. react 로부터 import 해줍니다.
  2. useState(초기값) 을 통해 초기값을 지정해줍니다.
  3. 상태를 변화시킬 때에는 set변수명 을 통해 변화시킵니다.
import React, { useState } from 'react';

const Info = () => {
  const [name, setName] = useState('');
  const [nickName, setNickName] = useState('');

  const onChangeName = e => {
    setName(e.target.value);
  };

  const onChangeNickName = e => {
    setNickName(e.target.value);
  };
  ...
}

useEffect

useEffect는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook입니다.

componentDidMountcomponentDidUpdate 를 합친 형태라고 볼 수 있습니다.

useEffect를 사용해보자!

reference code

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

const Info = () => {
  const [name, setName] = useState('');
  const [nickName, setNickName] = useState('');
  useEffect(() => {
    console.log('rendering ready');
    console.log({ name, nickName });
  });

  ...

};

export default Info;

위 처럼 작성할 경우, 렌더링이 될 때마다 useEffect가 불리게 됩니다.

마운트될 때만 useEffect를 사용해보자!

reference code

업데이트를 제외하고 처음 렌더링 할 때만 useEffect를 사용하려면 아래와 같이 두 번째 파라미터에 빈 값을 넣어줍니다.

useEffect(() => {
    console.log('only when mounted');
  }, []);

특정값이 업데이트될 때만 useEffect를 사용해보자!

reference code

특정값이 업데이트 될 때만 실행하고 싶다면 아래와 같이 모니터링하고 싶은 특정값을 두 번째 파라미터로 넣어줍니다.

useEffect(() => {
    console.log(name);
  }, [name]);

Cleanup

code reference

컴포넌트가 언마운트되기 전이나 업데이트 되기 전에 어떠한 작업을 수행하고 싶다면 useEffect 에 return으로 수행하고 싶은 cleanup함수를 넘겨줍니다.

useEffect(() => {
    console.log('effect');
    console.log(name);
    return (() => {
      console.log('cleanup');
      console.log(name);
    });
  }, [name]);

useReducer

reference code

useReducer 함수는 더 다양한 상황에 따라 다양한 상태의 다른 값을 업데이트 해줄 때에 사용하는 Hook입니다.

action을 통해 업데이트에 필요한 값을 전달 받아 새로운 상태를 반환합니다.

import React, { useState, useEffect, useReducer } from 'react';

function reducer(state, action) {
  return {
    ...state,
    [action.name]: action.value
  };
}

const Info = () => {
  const [state, dispatch] = useReducer(reducer, {
    name: '',
    nickName: ''
  });
  const { name, nickName } = state;
  const onChange = e => {
    dispatch(e.target);
  }

  ...

}

useMemo

sample code to refactor

위의 코드는 값이 추가될 때마다 평균값을 연산하는 코드입니다.

하지만, 로그를 확인해보면 버튼을 눌렀을 때만 값을 출력하는 것이 아니라 숫자가 변경될 때마다 getAverage 함수가 호출되는 것을 확인할 수 있습니다.

이렇게 버튼이 눌렸을 때만 연산을 수행해도 되는데 숫자가 변경될 때마다 연산을 수행하는 것을 방지하기 위해 useMemo를 사용합니다. 즉, 렌더링 성능을 최적화 시키는 데에 사용한다고 할 수 있습니다.

reference code

import React, { useState, useMemo } from 'react';

...

const Average = () => {

  ...

	const avg = useMemo(() => getAverage(list), [list]);

    return (
        <div>
            <input value={number} onChange={onChange} />
            <button onClick={onInsert}>Insert</button>
            <ul>
                {list.map((value, index) => (
                    <li key={index}>{value}</li>
                ))}
            </ul>
            <div>
                <b>Average:</b>{avg}
            </div>
        </div>
    );
}

이제, 숫자가 변화하는 것이 아니라 list 배열의 내용이 바뀔 때만 getAverage 함수가 호출됩니다.

useCallback

useCallback 도 렌더링 성능을 최적화시키는 데에 사용하는 함수입니다. useMemo와 다르게 useCallback 은 함수 재사용을 가능하게 하여 성능을 향상시킵니다.

const Average = () => {
    const [list, setList] = useState([]);
    const [number, setNumber] = useState('');

    const onChange = e => {
        setNumber(e.target.value);
    };

    const onInsert = e => {
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    };
		
		...
}

위의 코드는 컴포넌트가 리렌더링 될 때마다 onChange 함수와 onInsert 함수를 새로 생성합니다. 이러한 경우, 컴포넌트의 렌더링이 자주 발생하거나 컴포넌트의 개수가 많아질 때 최적화를 해주는 것이 좋습니다.

useCallback으로 함수 재생성을 최적화한 코드

const Average = () => {
    const [list, setList] = useState([]);
    const [number, setNumber] = useState('');

    const onChange = useCallback(e => {
        setNumber(e.target.value);
    }, []);

    const onInsert = useCallback(e => {
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    }, [number, list]);

    ...
}

위의 코드에서는 useCallback 을 통해 함수 생성을 최적화하였습니다. 첫 번째 파라미터에는 생성하고 싶은 함수를 넣고, 두 번째 파라미터에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지 명시합니다.

두 번째 파라미터에 빈 배열을 넣을 경우, 컴포넌트 렌더링 되었을 때 단 한 번만 함수가 생성되고, 값을 넣었을 경우, 해당 값에 변화가 있거나 새로운 항목이 추가될 경우 함수가 새로 생성됩니다.

useRef

useRef 는 함수형 컴포넌트에서 ref 를 쉽게 사용할 수 있도록 해줍니다. 아래는 버튼을 눌렀을 때, 포커스를 안쪽으로 넘어가도록 한 코드입니다.

reference code

import React, { useState, useMemo, useCallback, useRef } from 'react';

...

const Average = () => {
    const [list, setList] = useState([]);
    const [number, setNumber] = useState('');
    const inputE1 = useRef(null);

		...

    const onInsert = useCallback(e => {
        ... 
        inputE1.current.focus();
    }, [number, list]);

    const avg = useMemo(() => getAverage(list), [list]);

    return (
        <div>
            <input value={number} onChange={onChange} ref={inputE1} />
            ...
        </div>
    );
};

export default Average;

또한, useRef 는 렌더링과 관련되지 않은 값들을 관리할 때에 사용할 수 있습니다.

Hook 정리

  • useState : Component의 상태를 업데이트 할 때
  • useEffect : 컴포넌트가 렌더링 될 때 동작을 수행하도록 할 때
  • useReducer : 다양한 상태의 다양한 값을 업데이트 해줄 때
  • useMemo : 숫자, 문자열, 객체처럼 일반 값을 재사용할 때
  • useCallback : 함수를 재사용할 때
  • useRef : ref 를 사용할 때
profile
재밌는 것만 하고 싶어 ʕ•ﻌ•ʔ

0개의 댓글