[React] Hooks

박이레·2022년 11월 12일
0

React

목록 보기
9/12

 2019년 2월 6일, 페이스북은 리액트 v16.8을 발표합니다. React v16.8: The One With Hooks!

기존 함수 컴포넌트에서는 상태 관리, 렌더링 후 작업 설정을 할 수 없었는데, Hooks가 이 문제를 해결했습니다. Hooks 덕분에 페이스북은 클래스형 컴포넌트 대신 함수형 컴포넌트를 권장하게 됐습니다.

Hooks의 사용은 Function Programming의 첫 걸음입니다. Object Oriented Programming에 익숙한 제게 FP은 낯설었습니다. OOP도 완벽하게 사용하지 못하는데 또 무언가 배우는 것이 부담되기도 했습니다. 그러나 진화하기 위해선 변화해야 한다는 점을 되새기며 공부했습니다. 오늘보다 내일 더 발전된 사람이 되길 바랍니다 :)



useState

가장 기본적인 Hook입니다. 함수 컴포넌트에서도 가변적인 상태를 지닐 수 있게 해 줍니다.

① useState는 배열을 반환합니다.
② useState의 첫 번째 원소는 상태 값, 두 번째 원소는 상태를 설정합니다.
③ useState(0)으로 상태의 기본값을 초기화합니다. (value == 0)


import { useState } from 'react';

const Counter = () => {
  const [value, setValue] = useState(0);
  
  return (
    <>
    	<p>
    		현재 값은 {value}입니다.
  		</p>
		<button onClick={() => setValue(value + 1)}>+1</button>
		<button onClick={() => setValue(value - 1)}>-1</button>
	</>
);
};

export default Counter;

useEffect

컴포넌트가 렌더링될 때마다 특정 작업을 수행합니다. 클래스형 컴포넌트의 componentDidMountcomponentDidUpdate를 합친 형태입니다. 콜백 지옥을 벗어나게 해주는 중요한 Hook입니다.

<React.StrickMode>를 사용하면 useEffect가 두 번 호출됩니다. 코드에 문제 여부를 확인하기 위함입니다. 추후 컴포넌트가 사라졌다가 다시 나타나도 컴포넌트의 상태를 유지하는 기능이 도입될 거라고 합니다.

useEffect는 두 번째 파라미터가 중요합니다.
두 번째 파라미터에 어떤 배열을 넣느냐에 따라 실행 시점이 결정됩니다.

import { useState, useEffect } from 'raect;

const Info = () => {
  const [name, setName] = useState('');
  const [nickname, setNickname] = useState('');
  useEffect(() => {
    name,
    nickname
  });
});

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

const onChangeNickname = e => {
  setNickname(e.target.value);
};

return (
  (...)
);
};

export default Info;

마운트될 때만 실행하고 싶을 때

useEffect에서 설정한 함수가 초기 렌더링 때만 실행되고, 업데이트될 때는 실행되지 않게하려면 함수의 두 번째 파라미터로 빈 배열을 넣어주면 됩니다. 이는 콜백 지옥을 벗어나게 해줍니다.

useEffect(() => {
  
}, []);

업데이트될 때만 실행하고 싶을 때

마운트될 때만 실행하고 싶을 때와는 다르게 업데이트될 때만 실행하고 싶을 때는 두 번째 파라미터로 업데이트 되는 값을 넣어줍니다.

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

언마운트되기 전 && 업데이트되기 직전 실행하고 싶을 때

뒷정리 함수(cleanup)를 반환해주어야 합니다.

useEffect(() => {
  return () => {
  };
}, [name]);

useReducer

useState보다 더 다양한 상황에서 상태를 다른 값으로 업데이트할 때 사용합니다. useReducer는 현재 상태, 액션 값(업데이트를 위해 필요한 정보를 담은 것)을 전달받아 새로운 상태를 반환합니다.

useReducer에서 새로운 상태를 만들 때 반드시 불변성을 지켜야 합니다.

첫 번째 파라미터에는 reducer 함수를, 두 번째 파라미터에는 해당 reducer 함수의 기본값을 넣습니다.
reducer는 state와 dispatch를 반환합니다.
state는 현재 가리키고 있는 상태이고, dispatch는 액션을 발생시키는 함수입니다.

import { useReducer } from 'react';

fuction reducer(state, action) {
  // action.type에 따라 다른 작업을 수행합니다.
  switch (action.type) {
    case 'INCREMENT':
      return { value: state.value + 1 };
    case 'DECREMENT':
      return { value: state.value - 1 };
    default:
      return state;
  }
}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, {value: 0});
  
  return (
    <>
    	<p>
    		{state.value}
    	</p>
    	<button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
    	<button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
	</>
);
};

export default Counter;

useMemo

함수 컴포넌트 내부에서 발생하는 연산을 최적화합니다. 렌더링 과정에서 특정 값이 바뀌었을 때만 연산합니다. 값이 바뀌지 않았다면 이전에 연산한 결과를 다시 사용합니다.

import { useState, useMemo } from 'react;

const getAverage = numbers => {
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState('');
  
  const onChange = e => {
    setNumber(e.target.value);
  };
  
  const onInsert = () => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber('');
  };
  
  const avg = useMemo(() => getAverage(list), [list]);
  
  return (
    <>
    	<input value={number} onChange={onChange} />
    	<button onClick={onInsert}>등록</button>
		<ul>
          {list.map((value, index) => (
            <li key={index}>{value}</li>
		  )))};
        </ul>
		<>
          {avg}
		</>
	</>
);
};

export default Average;

useCallback

useMemo와 상당히 비슷합니다. 렌더링 성능을 최적화할 때 사용합니다. useCallback은 만들어 둔 함수를 재사용할 수 있게 해줍니다.

첫 번째 파미터에는 생성하고 싶은 함수를
두 번째 파라미터에는 배열을 넣으면 됩니다.
이 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지 명시합니다.

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

const getAverage = numbers => {
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a,b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState('');
  
  const onChange = useCallback(e => {
    setNumber(e.target.value);
  }, []);
  
  const onInsert = useCallback(() => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber('');
  }, [number, list]);
  
  const avg = useMemo(() => getAverage(list), [list]);
  
  return (
    <>
    	<input value={number} onChange={onChange} />
    	<button onClick={onInsert}>등록</button>
		<ul>
          {list.map((value, index) => (
            <li key={index}>{value}</li>
		))}		
		</ul>
		<>
          {avg}
		</>
	</>
);
};

export default Average;

useRef

함수 컴포넌트에서 ref를 쉽게 사용할 수 있게 해줍니다. useRef는 ref의 값이 바뀌어도 컴포넌트가 렌더링되지 않습니다. 렌더링에 관련되지 않은 값을 관리할 때 사용하면 유용합니다.

import { useRef } from 'react';

const RefSample = () => {
  const id = useRef(1);
  const setId = (n) => {
    id.current = n;
  }
  
  const printId = () => {
    conssole.log(id.current);
  }
  
  return (
    <>
    	refSample
    </>
    );
};

export default RefSample;

이 외에도 사용자 직접 Hook을 작성하여 사용할 수도 있습니다. Hooks 패턴을 사용하면 클래스형 컴포넌트를 사용하지 않고도 대부분의 기능을 구현할 수 있습니다.



💁‍♂️reference


리액트를 다루는 기술

김민준 지음ㅣ길벗ㅣ2019ㅣ도서 정보

EOD.

profile
혜화동 사는 Architect

0개의 댓글