Dev/Web

[React] Hook의 이해-1 (useState, useEffect)

더움바다 2023. 4. 18. 00:31

아마 다들 아시겠지만 React18버전 이후로 새로운 공식 문서가 나왔습니다. 

https://ko.reactjs.org/ (legacy) 

(reactjs.org는 사라졌는데 ko.reactjs.org는 안 사라졌더라구요.. 개발팀에서 뭔가 실수를 한것 같습니다)

 

React – 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리

A JavaScript library for building user interfaces

ko.reactjs.org

https://react.dev/ (current)

 

React

The library for web and native user interfaces

react.dev

 

Hook이 뭔지는 아마 다들 아실테지만.. 간단히 짚고 넘어가자면

Class Component가 아닌 Functional Component에서 React의 기능들을 지원해주는 함수입니다.

 

Class Component

import React from 'react';

export default class Test extends React.Component<any, any> {
  state = {
    count: 0,
  }

  constructor(props: any) {
    super(props);
  }

  increment() {
    this.setState({
      count: this.state.count + 1,
    })
  }

  decrement() {
    this.setState({
      count: this.state.count - 1,
    })
  }

  render() {
    return (
      <div>
        <button onClick={increment}>
          increment
        </button>
        <div>
          {this.state.count}
        </div>
        <button onClick={decrement}>
          decrement
        </button>
      </div>
    )
  }
}

 

Functional Component (with useState)

import {useState} from "react";

export default function Test() {
  const [count, setCount] = useState(0);
  
  const incremenet = () => setCount(prevState => prevState++);
  const decremeent = () => setCount(prevState => prevState--);
  
  return (
    <div>
      <button onClick={incremenet}>
        incremenet
      </button>
      <div>
        {count}
      </div>
      <button onClick={decremeent}>
        decrement
      </button>
    </div>
  )
}

흠.. 대략 이정도의 차이가 있겠네요.. 

쉽게 말씀을 드리자면 OOP vs Functional Programming정도의 차이일것 같습니다.

 

OOP (객체 지향형 프로그래밍)

Functional Programming (함수형 프로그래밍)

 

좋다 나쁘다 그런건 없겠지만 React에서는 Hook을 사용하여 보다 선언적으로 코드를 작성하는것을 권장하고 있으니 Hook을 사용하시는것을 추천드립니다.

 

그렇다면 이제 진짜 Hook소개를 시작하도록 하겠습니다.

 

1. useState

 

useState – React

The library for web and native user interfaces

react.dev

React는 상태 관리 라이브러리입니다. 

근데 useState는 아주 기본적인 상태를 관리하는 Hook입니다.

쉽게 말해 매우 중요합니다. 

기본적인 사용법을 설명드리자면 다음과 같습니다.

import { useState } from 'react';

function Test() {
  // default format: const [value, setValueFn] = useState(defaultValue);
  const [flag, setFlag] = useState(false);
}

여기서 Value에는 어떤 값이건 집어넣을 수 있습니다.

예를 들어.. 이런 Object도 넣을 수 있으며, Number, Boolean, String, Array등 다 가능합니다. 

import { useState } from 'react';

const obj = {
  a: 1,
  b: 2
}

function Test2() {
  // 이렇게 사용은 할수 있으나 이렇게 할 경우 값 변경을 할수 없기에 추천드리지 않습니다
  const [number] = useState(1);
  const [object, setObject] = useState(obj);
}

그리고 setValueFn 형식의 경우 두가지가 있습니다.

  • setValueFn((prevState: ValueType) => ValueType)
  • setValueFn(ValueType)
import {useState} from "react";

export default function Test3() {
  const [string, setString] = useState('string');

  return (
    <div>
      <div>
        {string}
      </div>
      <button onClick={() => setString(prevState => prevState + 'string')}>
        append string value to existing value
      </button>
      <button onClick={() => setString('')}>
        reset value
      </button>
    </div>
  )
}

 

 

2. useEffect

 

useEffect – React

The library for web and native user interfaces

react.dev

useEffect는 side effect를 관리해주는 hook입니다.

Side Effect에 대해서도 간단히 짚고 넘어가자면..

Side Effect(부작용): Component가 렌더링된 이후에 비동기로 처리되어야 하는 효과들입니다.

(ex. 외부 API호출, Dom조작, Storage조작등등..)

 

import {useEffect, useState} from "react";

export default function Test4() {
  const [string, setString] = useState('string');
  const [storageItem, setStorageItem] = useState('');

  useEffect(() => {
    // side effect (localstorage)
    const temp = window.localStorage.getItem('temp') ?? 'temp';
    setStorageItem(temp);
  }, []);

  return (
    <div>
      <div>
        {string}
      </div>
      <button onClick={() => setString(prevState => prevState + 'string')}>
        append string value to existing value
      </button>
      <button onClick={() => setString('')}>
        reset value
      </button>
    </div>
  )
}

 

본론으로 돌아가보자면, useEffect의 기본 형식은 다음과 같습니다.

function Test5() {
  // default format: useEffect(effectFn, deps)
  // deps를 빈배열로 세팅할 경우 컴포넌트가 마운트 됬을 경우에만 effectFn이 실행된다.
  // deps에 값을 세팅할 경우 값 변경 or 컴포넌트가 마운트 됬을 경우에 effectFn이 실행된다.
  useEffect(() => {
    
  }, []);
}

 

useEffect를 여러개 사용할 경우 위에서부터 순서대로 실행됩니다.

Test6 useEffect&nbsp; 실행모습

import {useEffect, useState} from "react";

export default function Test6() {
  const [string, setString] = useState('string');
  const [storageItem, setStorageItem] = useState('');

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

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

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

  return (
    <div>
      <div>
        {string}
      </div>
      <button onClick={() => setString(prevState => prevState + 'string')}>
        append string value to existing value
      </button>
      <button onClick={() => setString('')}>
        reset value
      </button>
    </div>
  )
}

 

또한 effectFn에서 return값은 정리(clean-up)역할을 합니다.

import {useEffect, useState} from "react";

export default function Test7() {
  const [string, setString] = useState('string');

  useEffect(() => {
    const interval = setInterval(() => console.log('1'), 1000);
    
    return () => {
      clearInterval(interval);
    }
  }, []);

  return (
    <div>
      <div>
        {string}
      </div>
      <button onClick={() => setString(prevState => prevState + 'string')}>
        append string value to existing value
      </button>
      <button onClick={() => setString('')}>
        reset value
      </button>
    </div>
  )
}

 

useEffect는 Side Effect를 다룰때 무척 유용한 Hook이지만, 오남용하게 될시 페이지의 성능을 떨어뜨리는 주된 범인이 되기도 합니다.

열심히 공부하셔서 잘 사용하시길 바랍니다.

긴 글 봐주셔서 감사합니다.