열렬히.뛰기

함수형 컴포넌트와 hook (1)

웹 프로그래밍 > React > 리액트의 기초 > 함수형 컴포넌트와 hook (1)

훅이란?

  • 리액트에는 컴포넌트와 그 안의 state라는 것이 존재한다.
  • 컴포넌트의 종류에는 2가지가 존재한다 : 클래스형, 함수형
    • 클래스형의 경우, state를 설정하는 것이 편했다.
    • 반면 함수형의 경우 직접 state를 설정하는 것이 불가능하다.
  • 따라서 이를 위해서 등장한 것이 바로 훅이다.
  • 대표적인 훅의 종류를 살펴보자.

useState

변수에 state를 걸어주는 함수

버튼을 누르면 그 값이 계속 올라게끔 리액트 코드를 짜보자.

javascript
import React, { useState } from "react";

function Counter(props) {
		var count = 0;

    return (
        <div>
            <p>총 {count}번 클릭했습니다.</p>
            <button onClick={() => setCount(count + 1)}>
                클릭
            </button>
        </div>
    )
}

export default Counter;

그런데, 이렇게 짜면 도저히 텍스트(”총 ..번 클릭했습니다”)가 바뀌지 않는다.

왜? count 값이 바뀌어도, 화면을 다시 그리지 않기(= 리렌더링이 안되기) 때문이다

따라서 state를 사용해서 바꿔줘야 한다.

javascript
import React, { useState } from "react";

function Counter(props) {
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>총 {count}번 클릭했습니다.</p>
            <button onClick={() => setCount(count + 1)}>
                클릭
            </button>
        </div>
    )
}

export default Counter;

인제 값이 바뀌는 것을 눈치챌 수 있다.

기본 공식

어떠한 변수에 state를 걸고 싶다면, 다음과 같이 설정하면 된다.

javascript
// 변수명 = num, 초깃값 = 0이라고 하면...
const [num, setnum] = useState(0)

useEffect

componentDidMount(), componentDidUpdate(), componentWillUnmount()를 묶어서 만들어낸 함수라고 생각하면 된다.

언제 쓰는가?

  1. 데이터 가져오기 (Fetching data): 컴포넌트가 처음 마운트될 때 서버로부터 데이터를 가져오는 작업을 수행.
  2. 구독 설정 및 해제 (Subscribing and unsubscribing): 웹소켓, 데이터 스트림, 이벤트 리스너 등 구독을 설정하고 컴포넌트가 언마운트될 때 구독을 해제.
  3. DOM 조작: 컴포넌트가 렌더링될 때 또는 업데이트될 때 직접 DOM을 조작하는 작업이 필요할 때 사용.
  4. 타이머 설정 (Timers): 타이머나 인터벌을 설정하고 해제.

왜 쓰는가?

  1. 코드 구조 개선: 흩어져 있는 생명주기 메서드(componentDidMount, componentDidUpdate, componentWillUnmount)를 하나로 모아 가독성을 높임.
  2. 명시적 의존성 관리: useEffect의 두 번째 인수로 의존성 배열을 전달하여, 어떤 값이 변경될 때 효과를 다시 실행할지 명시적으로 관리.
  3. 클린업 기능: 정리 함수(clean-up function)를 반환하여 컴포넌트가 언마운트될 때 또는 의존성이 변경될 때 실행할 정리 작업을 지정.

예제 코드

javascript
import React, { useState, useEffect } from "react";

function Counter(props) {
    const [count, setCount] = useState(0);

    useEffect(() => {
        console.log(`You clicked ${count} times`);

        return () => {
            console.log('Cleanup on component unmount');
            console.log('or before next effect runs');
        };
    }, [count]);

    return (
        <div>
            <p>총 {count}번 클릭했습니다.</p>
            <button onClick={() => setCount(count + 1)}>
                클릭
            </button>
        </div>
    )
}
export default Counter;
  • useEffect() 속의 코드들을 보자
  • console.log() : componentDidMount, componentDidUpdate 의 기능을 하고 있다.
  • return() : componentWillUnmount의 기능을 하고 있다.

useMemo

성능을 최적화한 useEffect()

언제 쓰나?

  1. 비용이 많이 드는 계산 : 배열의 정렬, 필터링, 맵핑 등 비용이 많이 드는 계산을 수행해야 할 때.
  2. 의존성 변경 시에만 재계산 : 특정 상태나 프롭이 변경될 때만 재계산이 필요할 때.
  3. 렌더링 최적화 : 동일한 결과를 반복적으로 계산하지 않고, 메모이제이션된 값을 사용하여 렌더링 성능을 최적화할 때.

조심할 점

  1. useMemo()로 전달된 함수는 렌더링이 일어나는 동안 실행.
  2. 따라서 렌더링이 일어나는 동안 실행되면 안되는 작업은 useEffect()를 사용
    • ex. 서버에서 데이터 받아오기, 수동으로 DOM 변경.
javascript
import React, { useState, useMemo } from 'react';

function XXX_Component() {
    const [count, setCount] = useState(0);
    const [otherValue, setOtherValue] = useState(0);

    // 비용이 많이 드는 계산을 useMemo로 최적화
    const expensiveResult = useMemo(() => {
        let result = 0;
        for (let i = 0; i < 1000000000; i++) {
            result += i;
        }
        return result + count;
    }, [count]); // count가 변경될 때만 재계산됨

    return (...);
}
export default XXX_Component;