Study/React

[새싹x코딩온] 웹 개발자 부트캠프 과정 13주차 회고 | React Hooks(2)

다니니니 2024. 8. 11. 02:06
728x90

 

이전 포스팅에 이어서

https://daddda3232.tistory.com/75

 

[새싹x코딩온] 웹 개발자 부트캠프 과정 13주차 회고 | React Hooks(1)

1. 들어가며리액트의 Hooks 살펴보기2. React HooksHook 이란?React 의 Hook은 함수형 컴포넌트에서 state(상태관리) 와 lifecycle(생명주기) 기능을 가능하게 해주는 기능이다. ✔ Hook은 클래스형 컴포넌트에

daddda3232.tistory.com

 

 

 

Hook 의 종류

다음에 설명할 hook 부터는 메모이제이션이라는 개념이 나온다.

 

메모이제이션이란?

컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술(중복 계산 방지)

대표적으로 useMemo 와 useCallback 이 메모이제이션을 통해 최적화를 할 수 있게 해주는 훅이다.

 

4) useMemo

메모이제이션을 통해 함수의 리턴값을 재사용할 수 있게 해주는 훅이다.

const memoizedValue = useMemo(callback, dependencies)
// 두번째 인자로 받은 의존 배열 값이 바뀌는 경우에만 첫번째 인자인 콜백함수 실행

//ex
const [count, setCount] = useState(0)
const calc = useMemo(()=>{
	return count ** 2;
}, [count]) // count 의 값이 변할때만 콜백함수 실행

 

5) useCallback

메모이제이션된 함수를 반환하는 함수

const memoizedCallback = useCallback(callback, dependency)
// 두번째 인자로 받은 의존성 배열 값이 변하지 않는다면, 리렌더링되어도 함수는 새로 생성되지 않음

 

🤷‍♀️ useEffect도 의존성 배열 값이 변할 때 실행하게 할 수 있는데, 굳이 useMemo와 useCallback을 사용하는 이유는?
만약 컴포넌트 내의 함수가 복잡한 연산을 수행하면 결과 값을 리턴하는데 오랜 시간이 걸릴 수 있다.
이 때,  컴포넌트가 계속 리렌더링 된다면 리렌더링 될때마다 연산을 계속 수행하고 그에 따라 성능에 영향을 미치게 된다.
(리렌더링 될때마다 UI가 나오는걸 오래 기다려야 한다는 등의 불편함이 발생할 수 있음)
useMemo 를 통해서 복잡한 연산 결과를 메모이제이션 해서 불필요한 연산을 최소화하여 성능 최적화를 할 수 있다.
(컴포넌트가 리렌더링되어도 연산값이 같다면 연산을 다시 하지 않고 이전에 렌더링할 때 저장해두었던 값 재활용)

컴포넌트가 렌더링 될 때 함수도 만들게 되는데, 리렌더링 될때마다 함수를 다시 만든다.
컴포넌트가 리렌더링 될 때마다 함수를 다시 만드는 것은 최적화 측면에서 좋지 않다. 
useCallback 을 통해 함수를 기억하게 해서 리렌더링될 때마다 의존성 배열의 값이 바뀌지 않는 한 기존 함수를 다시 생성하지 않고 재사용할 수 있다. 

즉! useEffect와 useMemo는 비슷한 기능처럼 보일지라도 사용 목적이 다르다.
useEffect는 라이프사이클에 관련된 훅이고 useMemo와 useCallback은 메모이제이션을 통한 성능 최적화를 위한 훅이다

 

6) useReducer

컴포넌트에 Reducer를 추가하는 훅이다.

Reducer란 현재 상태와 업데이트를 위해 필요한 정보를 담은 액션 값을 전달받아 새로운 상태를 반환하는 함수다.

const [state, dispatch] = useReducer(reducer, initalState)
// state : 현재 상태
// dispatch :  액션을 발생시키는 함수
// reducer : state를 업데이트 하는 함수
// initialState : 상태의 초기값

 

useReducer는 useState보다 복잡한 상태 관리에 필요한 경우에 사용한다.(배열이라든지.. 객체라든지 하위요소가 많은 경우에)

 

기존에 이전 포스팅(react state : https://daddda3232.tistory.com/72)에서 useState를 통해 구현했던 것을 useReducer로 리팩토링 해보고자 한다.

 

useState를 이용했던 기존 코드

// useState를 이용한 기존 코드
function App() {
 // 주민 정보 배열
  const villager= [
    {name : '릴리안', birthday : '5월 9일생'},
    {name : '쭈니', birthday : '9월 29일생'},
    {name : '아네사', birthday : '6월 23일생'},
    {name : '리키', birthday : '6월 3일생'},
    {name : '마티', birthday : '4월 16일생'},
    {name : '스파크', birthday : '7월 9일생'},
    {name : '레베카', birthday : '9월 10일생'},
    {name : '미애', birthday : '3월 10일생'},
    {name : '스피카', birthday : '9월 11일생'},
    {name : '미첼', birthday : '5월 19일생'},
  
  // state
  const [name, setName] = useState('릴리안')
  const [day, setDay] = useState('5월 9일생')

  // 클릭이벤트 함수
  const clickVillger = (e) => {
    let vName = e.currentTarget.innerText
    let vDay = e.currentTarget.lastChild.getAttribute('data-day')
    setName(vName)
    setDay(vDay)
  }

  return (
    <div className="App">
      <Villagers villager={villager} click={clickVillger}/>
      <VillagerInfo name={name} day={day}/>
    </div>
  );
}

useState를 2개를 지정해서 클릭할 때 name과 day 함수가 바뀌도록 구현했다.

 

useReducer로 리팩토링한 코드

// useReducer로 리팩토링한 코드

// 주민 정보 배열
const villagers= [
  {id : '1', name : '릴리안', birthday : '5월 9일생'},
  {id : '2', name : '쭈니', birthday : '9월 29일생'},
  {id : '3', name : '아네사', birthday : '6월 23일생'},
  {id : '4', name : '리키', birthday : '6월 3일생'},
  {id : '5', name : '마티', birthday : '4월 16일생'},
  {id : '6', name : '스파크', birthday : '7월 9일생'},
  {id : '7', name : '레베카', birthday : '9월 10일생'},
  {id : '8', name : '미애', birthday : '3월 10일생'},
  {id : '9', name : '스피카', birthday : '9월 11일생'},
  {id : '10', name : '미첼', birthday : '5월 19일생'},
]

// 초기 상태값
const initState = villagers[0]

// reducer 함수
const reducer = (prevState, action) => {
  return prevState = villagers[action - 1]
}

function App() {
  // useReducer 훅 
  const [villager, dispatch] = useReducer(reducer, initState)  

  // 액션 핸들러 함수
  const clickVillger = (e) => {
    let vId = e.currentTarget.getAttribute('data-list')
    dispatch(vId)
  }

  return (
    <div className="App">
      <Villagers villager={villagers} click={clickVillger}/>
      <VillagerInfo name={villager.name} day={villager.birthday}/>
    </div>
  );
}

useReducer를 통해 클릭했을 때, 배열데이터의 인덱스 값을 바꿔서 데이터를 갱신하는 방법으로 리팩토링 해줬다.

 

결과

 

 

 

 

3. 마치며

리액트에서 사용하는 여러가지 훅에 대해 알아보았다.

여기있는 훅 뿐만 아니라 다른 훅들도 많고 심지어 직접 훅을 커스텀해서 사용할 수도 있다.

useEffect, useMemo, useCallback 에 대해서 헷갈렸는데 정리를 해보니 조금은 감이 잡힌다.

직접 코드를 짜서 사용해보면 조금 더 이해할 수 있지 않을까?

 

4. Reference

1. 코딩온 강의 교안 및 실습

 

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

 

Hook 개요 – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

 

 

3. https://ko.react.dev/reference/react/hooks

 

내장된 React Hook – React

The library for web and native user interfaces

ko.react.dev

 

 

728x90