[React] Hooks

SOL·2023년 8월 11일
0

React

목록 보기
5/8
post-thumbnail

Hooks는 리액트 v.16.8에 새로 도입된 기능으로, 함수 컴포넌트에서도 상태관리 기능과 라이프 사이클과 유사한 기능들을 사용할 수 있게 되었습니다. 또 컴포넌트의 성능 향상에 도움이 되는 Hook들도 있습니다.



useState

useState는 가장 기본적인 Hooks로, 함수 컴포넌트에서도 상태관리를 할 수 있습니다.

useState 함수의 인자에는 상태의 초기값을 넣어줍니다. 함수를 호출하면 배열이 반환되는데 첫 번째 원소는 현재 상태이고, 두 번째 원소는 상태를 바꾸어 주는 함수 입니다. 이 함수를 세터(Setter)함수라고도 부릅니다. 현재 상태를 변경할 때는 무조건 세터 함수를 통해서만 바꿔야합니다.

import { useState } from 'react';

const MyComponent = () => {
	const [message, setMessage] = useState('');
  	const onClick = () => {
    	setMessage('안녕하세요')
    };
  
  	return (
    	<div>
      		<button onClick={onClick}> 클릭! </button>
			<h1>{message}</h1>
      	<div>
    );
};

export default MyComponent;


useEffect

함수형 컴포넌트에서는 useEffect Hook을 사용하여 렌더링될 때마다 특정 작업을 수행할 수 있습니다. 클래스형 컴포넌트의 componentDidMout와 componentDidUpdate를 합친 형태로 보아도 무방합니다.

마운트 될때

useEffect에서 설정한 함수는 컴포넌트가 화면에 맨 처음 렌더링될 때만 실행됩니다. 업데이트될 때 실행하지 않으려면 함수의 두번째 파라미터로 비어있는 배열을 넣어주면 됩니다.

useEffect(()=>{
	console.log('여기 코드는 마운트될 때만 실행됩니다.')
},[]);

특정 값이 업데이트될 때

useEffect에서 설정한 함수의 두 번째 파라미터의 배열안에 검사하고 싶은 값을 넣어주면 됩니다. 검사하고 싶은 값은 useState로 관리하고 있는 상태 또는 props로 전달받을 값을 넣어주어도 됩니다.

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

언마운트 되기 전 또는 엡데이트되기 직전

useEffect에서 뒷정리(cleanup) 함수를 return 해주어야 합니다. 언마운트될 때만 뒷정리 함수를 호출하고 싶다면 useEffect 함수의 두 번째 파라미터에 비어있는 배열을 넣으면 됩니다.

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


useMemo

useMemo를 사용하면 함수형 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있습니다. Memo는 Momoization을 뜻합니다. Momoization은 동일한 값을 return 하는 함수를 반복적으로 호출해야 한다면, 맨 처음 계산한 값을 메모리에 저장해놓고 필요할 때마다 꺼내서 재사용하는 기법입니다.

함수는 호출될 때마다 그안에 정의해놨던 모든 변수들이 초기화됩니다. 다음 컴포넌트는 렌더링 될 때마다 value 라는 변수의 값이 10으로 초기화됩니다.

const MyCompoment = () => {
  	const calculate = () => {
    	return 10;
    }
    
	const value = calculate();
  
  	return <div>{value}</div>;
}

export default MyCompoment;

만약 calculate() 함수가 굉장히 복잡한 연산을 하는 함수라면 매번 렌더링 될때마다 반복해서 작업하는 것은 매우 비효율적입니다. 이때 useMemo Hook을 통해 성능 개선을 시도할 수 있습니다.

useMemo()는 두개의 인자를 받습니다. 첫 번째 인자는 콜백 함수, 두 번째 인자는 의존성 배열을 받습니다. 콜백 함수에는 우리가 Momoization할 값을 return 해줍니다. 의존성 배열에 값이 들어있다면 그 값이 업데이트 될 때만 콜백 함수를 재 호출합니다. 만약 배열이 비어있다면 컴포넌트가 맨 처음 마운트 될 때만 콜백 함수를 호출하고 이후에는 호출되지 않고 메모된 값을 사용하게 됩니다.

import { useMemo } from 'react'; 

const MyCompoment = () => {
  	const calculate = () => {
    	return 10;
    }
    
	const value = useMemo(()=>{
    	return calculate();
    },[]);
  
  	return <div>{value}</div>;
}

export default MyCompoment;

이제 MyCompoment가 계속 렌더링 되어도 calculate()가 다시 호출되지 않습니다.

useMemo()는 컴포넌트의 성능 최적화를 위해 사용되지만, 무분별하게 사용 시 오히려 성능이 더 안좋아집니다. 메모리를 따로 사용해서 값을 저장하기 때문입니다. 따라서 시간이 오래걸리는 복잡한 연산이 동반된 꼭 필요한 값만 Momoization하는 것이 좋습니다.



useCallback

useCallback은 useMemo와 상당히 비슷한 함수로, Momoization 기법을 이용해 컴포넌트의 성능을 최적화할 때 쓰입니다. useMemo와의 차이점은 인자로 받은 콜백 함수 자체를 Momoization해두는 것입니다.

함수형 컴포넌트는 함수이기 때문에 렌더링 될 때마다 그 안의 변수값들이 초기화됩니다. 자바스크립트에서의 함수는 변수에 따로 할당하여 사용할 수 있는데 재렌더링 될 때마다 함수 객체가 새로만들어져 변수에 할당됩니다.

useCallback을 이용하면 렌더링 될 때마다 함수 객체를 새로 만들지 않고 만들어뒀던 함수를 재사용할 수 있습니다. useCallback을()은 두개의 인자를 받습니다. 첫 번째 인자는 콜백 함수, 두 번째 인자는 의존성 배열을 받습니다.

import { useCallback } from 'react'; 

const MyCompoment = () => {
  	const calculate = useCallback((num) => {
    	return num+1;
    },[]);
    
	const value = calculate(3);
  
  	return <div>{value}</div>;
}

export default MyCompoment;


useRef

useRef는 함수형 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해줍니다. ref는 reference의 줄임말로 HTML에서 id를 사용하듯이 리액트에서 DOM에 이름을 다는 방법입니다. 추가로 컴포넌트 로컬 변수를 사용해야 할 때도 useRef를 활용할 수 있습니다.

useRef 문법은 다음과 같습니다. useRef 안의 인자로 넣어준 초기값은 ref 오브젝트 안의 { current: value }에 저장됩니다. ref의 값은 컴포넌트가 브라우저에 마운트 될 때부터 언마운트 될 때까지 계속 유지됩니다.

const ref = useRef(value);

ref 오브젝트는 언제든지 수정가능하기 때문에 ref.current 로 value를 꺼내 쓸 수 있습니다.

const ref = useRef('hi');
console.log(ref.current); //hi

useRef를 사용하기 유용한 두가지 상황이 있습니다. 첫 번째는 state와 같이 어떤 값을 저장해 둘 때 사용합니다.

함수형 컴포넌트에서 state를 변경하면 자동으로 리렌더링 되어 컴포넌트 내부의 모든 변수들이 초기화됩니다. 이때 리렌더링을 원하지 않는다면 ref에 값을 담아두면 됩니다. ref의 값은 아무리 변경되어도 렌더링이 다시 일어나지 않습니다. 따라서 ref를 이용해 불필요한 렌더링을 막으면 다른 변수들의 값을 유지시킬 수 있습니다. 또한 반대로 state값들이 변경되어 아무리 리렌더링이 일어나더라도 ref의 값은 유지됩니다.

변경시 렌더링을 일으키지 말아야하는 변수들은 ref에 담아두면 좋습니다.

import { useRef } from 'react'; 

const MyCompoment = () => {
	const id = useRef(3);
  	const setId = () => {
      id.current = id.current + 1;
      console.log(id.current);
    }
  
  	return <button onClick={setId()}>{id.current}</button>;
}

export default MyCompoment;

아무리 버튼을 클릭해서 ref의 값을 변경시켜도 화면에서는 변경된 값으로 바뀌지 않습니다.(콘솔 로그에는 변경된 값이 출력됩니다.) 이는 ref의 값이 변경되더라도 리렌더링이 일어나지 않기 때문입니다. 다른 state 변수로 인해 리렌더링이 일어날 시 ref 현재 값이 제대로 보이게될 것입니다.

만약 변화값을 감지해야지만 그 변화가 리렌더링을 일으키지 말아야할 때 useRef를 사용하면 좋습니다.


두 번째는 DOM 요소에 직접 접근할 때 사용합니다. 보통 input 요소에 focus를 주고싶을 때 많이 사용합니다.

import { useRef } from 'react'; 

const MyCompoment = () => {
  	const inputEl = useRef();
  
  	useEffect(()=>{
    	inputEl.current.focus();
    },[]);
	  
  	return (
      <div>
      	<input type="text" ref={inputEl} />
      </div>
    );
}

export default MyCompoment;
profile
개발 개념 정리

0개의 댓글

관련 채용 정보