2023. 3. 22. 11:22ㆍ코드스테이츠/코드스테이츠S4 Chapter & Unit
Hook이란?
Hook은 함수형 컴포넌트에서 상태 값 및 다른 여러 기능을 사용하기 편리하게 해주는 메소드를 의미한다.
Hook은 class형 컴포넌트가 아닌 함수형 컴포넌트에서만 사용할 수 있게 도와주는 것이기 떄문에 클래스형 컴포넌트에서는 작동하지 않는다.
함수형 컴포넌트와 클래스형 컴포넌트의 차이를 보기위해 버튼을 클릭하면 카운트가 1 증가하는 기능을 가진 컴포넌트를 두가지로 구현해보겠다.
클래스형 컴포넌트
//this 개념을 정확히 이해하지못하면 기능구현자체가 힘들 수 있고, 직관성 또한 떨어진다.
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0
}
this.handleIncrease = this.handleIncrease.bind(this);
}
handleIncrease = () => {
this.setState({
counter: this.state.counter + 1
})
}
render(){
return (
<div>
<p>You clicked {this.state.counter} times</p>
<button onClick={this.handleIncrease}>
Click me
</button>
</div>
)
}
}
함수형 컴포넌트
//어떤 기능을 하는 컴포넌트인지 매우직관적이다.
function Counter () {
const [counter, setCounter] = useState(0);
const handleIncrease = () => {
setCounter(counter + 1)
}
return (
<div>
<p>You clicked {counter} times</p>
<button onClick={handleIncrease}>
Click me
</button>
</div>
)
}
함수형 컴포넌트는 클래스형 컴포넌트에 비해 훨씬 더 직관적이고, 보기 쉽다는 특징이 있다. 이 Counter 컴포넌트에서 숫자를 올리기 위해 상태값을 저장하고 사용할 수 있게 해주는 useState() 가 있는데, 이 메서드가 바로 Hook이다.
Hook 사용 규칙
1. 리액트 함수의 최상위에서만 호출해야 합니다.
반복문, 조건문, 중첩된 함수 내에서 Hook을 실행하면 예상한 대로 동작하지 않을 우려가 있습니다.
2. 오직 리액트 함수 내에서만 사용되어야 합니다.
이는 리액트 함수형 컴포넌트나 커스텀 Hook이 아닌 다른 일반 JavaScript 함수 안에서 호출해서는 안 된다는 의미입니다.
Hook의 종류
useMemo란?
useMemo는 특정값을 재사용하고자 할 때 사용하는 Hook이다.
function Calculator({value}){
const result = calculate(value);
return <>
<div>
{result}
</div>
</>;
}
Calculator의 인자로 vlaue라는 props가 내려오면, 그 value를 calculate라는 함수에 넘겨서 나온 리턴값을 result라는 변수에 할당하여 사용하고있다. 그렇다면 렌더링이 될 때 마다 calculate라는 함수를 실행할 것 이고, 그 때마다 시간이 몇 초이상 소요될것이다. 그렇다면 값이 변하지 않는데 굳이 함수를 재실행 해야하는가? 값이 그대로라면 함수를 실행 할 필요없이 기존에 값을 재사용하면 좋지않을까? 해서 만들어진게 useMemo다.
사용법을 알아보자.
/* useMemo를 사용하기 전에는 꼭 import해서 불러와야 합니다. */
import { useMemo } from "react";
function Calculator({value}){
const result = useMemo(() => calculate(value), [value]);
return <>
<div>
{result}
</div>
</>;
}
이번에는 result에 calculate(value)를 할당하는게 아닌, useMemo()를 할당하고 첫번째 인자로는 콜백함수, 두번째인자는 디펜던시 어레이, 즉 두번째 인자의 상태가 바뀔 때 콜백함수를 실행해준다. 이런 식으로 useMemo를 호출하여 calculate를 감싸주면, 이전에 구축된 렌더링과 새로이 구축되는 렌더링을 비교해 value값이 동일할 경우에는 이전 렌더링의 value값을 그대로 재활용할 수 있게 된다.이는 메모이제이션(Memoization) 개념과 긴밀한 관계가 있다.
useMemo 실습
import React, { useState, useMemo, useEffect } from "react";
import "./styles.css";
//import { add } from "./add";
export default function App() {
const [number, setNumber] = useState(0);
const [isKorea, setIsKorea] = useState(true);
// 로케이션값이 원시타입이아닌 오브젝트타입이라면, 같은 값으로 보여도 렌더링마다 새로운 주소값을 받기때문에 usEffect는
// 로케이션의 상태가 바뀐다고 인지하기때문에 location을 변경하지않고, number의 상태를 바꿔주어도 렌더링이 진행되면서
// useEffect안에 콜백함수가 실행된다
/*
/isKorea의 상태가 바뀌어야만 location의 상태를 변경시키고,
location의 상태가 바뀌어야만 useEffect의 콜백함수가 실행된다.
결국엔 isKorea의 상태를 변경되는 순간에만 useEffect의 콜백함수가 실행된다.
뭔가 클로저함수의 쓰임새와 묘하게 닮았다.
*/
const location = useMemo(() => {
return {
country: isKorea ? "한국" : "외국"
};
}, [isKorea]);
useEffect(() => {
//많은 작업을 처리해야하거나, 무거운 함수를 실행시키는경우에는
//필요한 순간에만 useEffect를 실행하는게 효율적이다.
console.log("useEffect 호출함");
}, [location]);
return (
<div>
<h2>하루에 몇끼 먹어요?</h2>
<input
type="number"
value={number}
onChange={(e) => setNumber(e.target.value)}
/>
<h2>어느 나라에 있어요?</h2>
<p>나라 : {location.country}</p>
<button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
</div>
);
}
useMemo를 학습하면서 느낀 점.
useMemo와 useEffect, useCallback 그리고 동작방식이 뭐가 다른거지? 라는 생각이 들었다.
언뜻 봤을 때, useMemo의 기능을 useEffect가 대신 할 수 있는거 아닌가? 싶었는데, 비슷하지만 미묘한 차이가있었다.
useEffect
- 무언가(이 무언가는 디펜던시 어레이로 설정이 가능하다.)가 바뀌면 어떠한 동작(콜백함수)를 자동으로 실행하기 위해 사용한다.
- 인라인 콜백함수 : 디펜던시 어레이에 있는 항목 중 하나가 상태가 바뀌게 되면 실행시킬 동작
- 디펜던시 어레이 : 이 리스트에 있는 요소의 상태가바뀌면 콜백함수를 다시 실행시킨다.
useMemo
메모이제이션된 '값'을 반환한다.
useMemo는 함수를 실행
- useMemo는 원하는 값을 업데이트하기 위해 사용
- 인라인 콜백함수 : 디펜던시 어레이에 있는 항목 중 하나가 상태가 바뀌게 업데이트 할 값
- 디펜던시 어레이 : 이 리스트에 있는 요소의 상태가바뀌면 상태의 값을 바꾼다.
useCallback
메모이제이션된 '함수'를 반환한다.
seCallback은 함수를 반환
- 원하는 타이밍에 호출시킬 함수를 만들기 위해 사용 (함수를 리턴함)
- 인라인 콜백함수 : 원하는 타이밍에 동작시킬 동작
- 디펜던시 어레이 : 의존성에 포함된 요소가 업데이트 될 경우, 반환되는 함수도 갱신됨
비교
- useEffect vs useCallback
useEffect는 어떤 값의 변화가 동작을 자동으로 불러오도록 하고 싶을때,
useCallback은 어떤 값이 변했을때 특정 동작을 값에 따라 다르게 실행시키고 싶거나 원하는 타이밍에 어떤 동작을 실행시키고 싶을때 적합하다.
state를 바라보고 있다가 effect를 주는 것인데 이때의 effect는 멱등성이 유지된다.
그에 비해 useCallback은 state에 따라 다른 동작을 하는 함수를 리턴할 수 있을므로 동작을 state에 따라 다르게 주고 싶을때 유용하다.
- useMemo는 값을 리턴하며, 최적화에 방점이 찍힌다.
- 처음 React를 공부하기 시작했을때 용도가 비슷해보이는 것이 여러개 있어 어떤 때에 무엇을 써야할 지 몰랐는데, 사용하다보니 필요한 곳을 알게되는 것 같다. useEffect, useCallback, useMemo도 글로 이해하려는 것보다는 계속해서 사용해보고 예시를 많이 보는게 이해가 빠르게 될 것 같다.
useState와 useMemo의 사용처 비교
- useState를 쓸 수 밖에 없는 상황을 제외하고는 useMemo로 감싼 const로 선언하여 사용하는 것이 좋다.
- 아래처럼 의존성에 따라 값이 자동적으로 바뀌는 경우에는 useState를 사용할 이유가 없다.(자동 갱신에 가까운 느낌)
// b와 c를 더한 값이 a가 되는 경우
const a = useMemo(() => {b + c}, [b, c]);
- 그러나 아래의 경우처럼 server에서 값을 받아오거나 사용자로부터 입력을 받는 경우(onChange마다 변경이 일어남)에는 useState를 사용한다.
// useState를 쓸 수 밖에 없는 상황
const [ name, setName ] = useState('');
const [ email, setEmail ] = useState('');
(생략)
// 1. get data from server
fetch(domain).then((res) => setName(res.data.name));
(생략)
// 2. get data from user input
return (
<Form>
<label css={labelStyle} htmlFor='email'> Email </label>
<input
type='email'
id='email'
value={email}
(...)
onChange={(event) => setEmail(event.currentTarget.value)}
/>
</Form>
)
'코드스테이츠 > 코드스테이츠S4 Chapter & Unit' 카테고리의 다른 글
[Deploy]CI/CD (0) | 2023.04.03 |
---|---|
[Deploy] Amazon Web Service (0) | 2023.03.31 |
[React] Virtual DOM (0) | 2023.03.22 |
[React] 번들링과 웹팩 (0) | 2023.03.20 |
[HTML/CSS] 웹의 동작원리 (0) | 2023.03.20 |