[React] Hooks과 useState(), useEffect()

BGwon_C·2022년 12월 15일
0

React

목록 보기
2/3
post-thumbnail

리액트에 대해 공부하던 중 훅(Hooks)의 개념을 알게 되었고 이와 관련하여 체계적으로 정리할 필요성을 느꼈습니다.
전반적으로 저처럼 처음 입문하는 사람이 이해하기 쉽도록 작성하려 하였기에 개념을 아시는 분이 보시기엔 다소 길어질 수도 있는 내용입니다.

Hooks 이란?

리액트 v16.8 에 새로 도입된 기능으로서, "함수형 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 연동, 연결 (hook into) 해주는 함수"(출처: 리액트 공식문서) 로 정의할 수 있습니다.

무슨 말인지 좀 더 자세히 설명하자면,
기존의 함수형 컴포넌트에서는 클래스형 컴포넌트에 비해 다양한 작업을 하는 데 제약이 있었습니다.
예를 들자면, 상태 관리를 할 수 있는 useState, 그리고 렌더링 직후 작업을 설정하는 useEffect 등의 기능등을 사용할 수 었없지요.
그래서 Hooks을 추가하면서 기존 클래스형 함수에서 사용하던 상탯값,생명주기,Ref 등 여러가지 기능들을 함수형 컴포넌트에서도 사용할 수 있게 만들었습니다.


▼ 기존에 주로 이용하던 클래스형 컴포넌트는 여러가지 문제점들을 가지고 있었습니다.

클래스형 컴포넌트의 단점

  • 클래스형 컴포넌트에서 로직 재사용시에 사용하는 고차컴포넌트, 렌더속성값 패턴은 리액트 요소 트리를 깊게만든다. 따라서 성능에 부정적인영향과 개발 시 디버깅이 힘들어지는 문제점이 발생한다.
  • 서로 연관성없는 로직들을 하나의 생명주기에서 작성해야 하는 경우가 발생한다.
  • componentDidMount와 componentWillUnmount, comopnentDidMount와 componentDidUpdate처럼 반복해서 작성해야 하는 코드 발생
  • 컴퓨터 입장에서도 클래스 사용시 코드압축이 잘 안되는 경우,핫 리로드에서 난해한 버그 발생, 컴파일 단계에서 코드 최적화 어려움 발생
  • JS의 클래스문법, this 에 대한 이해가 필요

즉, React의 진입장벽을 높이는 데 클래스형 컴포넌트가 일조했던 셈입니다.

▼ 반면에 훅을 사용하면 다음과 같은 장점이 있습니다.

훅의 장점

  • 여러 훅들 끼리 재조립 가능하므로, 재사용 가능한 로직을 쉽게 만들 수 있다.
  • 로직을 한 곳에 모을 수 있다.
  • 훅은 단순한 함수이기 때문에 정적타입 언어에서도 타입을 쉽게 작성할 수 있다.

훅의 종류에는 여러가지가 있지만 이번 포스팅에서는 대표적인 2가지만 소개하겠습니다.


1. useState

(참고 : 리액트 공식문서)

- 개념 :

함수형 컴포넌트에서 상탯값을 관리(상태관리)하게 해주는 Hook

- 설명 :

useState 는 가장 기본적인 Hook 으로서, 함수형 컴포넌트에서도 가변적이고 동적인 상태를 지니고 있을 수 있게 해줍니다. 만약에 함수형 컴포넌트에서 상태를 관리해야 되는 일이 발생한다면 이 Hook 을 사용하시면 됩니다
(React에서는 컴포넌트에서 동적인 값을 상태(state)라고 부릅니다. 추가정보)

- 기본 구조 :

const [state, setState] = useState(initialState);
const [ 데이터, 데이터변경함수 ] = useState(초기값(생략가능));

초기값을 매개변수로 useState를 호출하면 첫 번째, 두 번째 요소에 각각 state와 setState를 받을 수 있습니다.
배열 비구조화 문법을 이용해 받는 것이기 때문에, state와 setState의 이름은 임의로 정할 수 있습니다.

- 사용법 :

react 모듈에서 { useState }를 import해서 불러오고, useState()를 선언해서 사용하면 됩니다. useState의 변수값이 바뀌면 컴포넌트가 새롭게 렌더링 됩니다.
예를 들어보죠

- 사용예 1)

import React, { useState } from 'react';

const Counter = () => {
  const [value, setValue] = useState(0);
  return (
    <div>
      <p>
        현재 카운터 값은 <b>{value}</b> 입니다.
      </p>
      <button onClick={() => setValue(value + 1)}>+1</button>
      <button onClick={() => setValue(value - 1)}>-1</button>
    </div>
  );
};코드를 입력하세요

이 함수의 파라미터에는 상태의 기본값(초기값)을 넣어줍니다. 우리는 현재 0 을 넣어줬는데, 결국 카운터의 기본값을 0 으로 설정하겠다는 의미입니다. 이 함수가 호출되고 나면 배열을 반환하는데요, 그 배열의 첫번째 원소는 상태 값(데이터)이고, 두번째 원소는 상태를 설정하는 함수(데이터 변경함수)입니다. 이 함수에 파라미터를 넣어서 호출하게 되면 전달받은 파라미터로 값이 바뀌게 되고 컴포넌트는 정상적으로 리렌더링 됩니다.

코드를 다 작성하고, 이해하셨다면 App.js 컴포넌트를 열어서 기존에 보여주고 있던 내용을 다 지우시고 Counter 컴포넌트를 렌더링하세요.

import React from 'react';
import Counter from './Counter';

const App = () => {
  return <Counter />;
};

export default App;

그럼 아래와 같이 결과가 나오는 것을 볼 수 있습니다.

- 사용예 2)

import React, { useState } from 'react'
export default function Profile () {
    const [name,setName] = useState('');
    return (
        <div>
            <p>{`name is ${name}`}</p>
            <input type='text' value={name} onChange={e=>setName(e.target.value)}></input>
        </div>
    )
}

클래스형 컴포넌트가 아니기 때문에 인스턴스가 없습니다.
this로 호출하는게 아닌 name, setName처럼 변수에 담긴 메서드와 값을 사용합니다.

- 여러개의 useState() 사용하기

하나의 useState 함수는 하나의 상태 값만 관리를 할 수 있기 때문에 만약에 컴포넌트에서 관리해야 할 상태가 여러 개라면 useState 를 여러번 사용하시면 됩니다.

  • 사용예 1)

import React, { useState } from 'react'

export default function Profile () {
    const [name,setName] = useState('');
    const [age,setAge] = useState(0);
    return (
        <div>
            <p>{`name is ${name}`}</p>
            <p>{`age is ${age}`}</p>
            <input type='text' value={name} onChange={e=>setName(e.target.value)}></input>
            <input type='text' value={age} onChange={e=>setAge(e.target.value)}></input>
        </div>
    )
}

여러개의 상탯값을 사용하는 코드입니다. 필요한 만큼 훅을 호출할 수 있습니다. 리액트가 훅이 호출된 순서를 기억해서 활용하므로 여러번 호출해도 문제되지 않습니다.

  • 사용예 2)

import React, { useState } from 'react';

const Info = () => {
  const [name, setName] = useState('');
  const [nickname, setNickname] = useState('');

  const onChangeName = e => {
    setName(e.target.value);
  };

  const onChangeNickname = e => {
    setNickname(e.target.value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={onChangeName} />
        <input value={nickname} onChange={onChangeNickname} />
      </div>
      <div>
        <div>
          <b>이름:</b> {name}
        </div>
        <div>
          <b>닉네임: </b>
          {nickname}
        </div>
      </div>
    </div>
  );
};

export default Info;

이번엔 좀 긴 예시이지만 별거 없습니다.
input태그에 onChange 속성값으로 onChangeName, onChangeNickname객체를 준 후 이 객체를 위에서 상수(const)로 정의한 것 뿐입니다.

이 코드를 작성후 App.js에서 렌더링하면 결과가 아래와 같이 나옵니다.
인풋내용을 변경하면서 확인해보시기 바랍니다.

- 하나의 useState()로 여러 상탯값 관리하기 (객체)

클래스형 컴포넌트에서 상탯값을 관리하는 것과 마찬가지로 객체형태로 관리할 수도 있습니다.
주의할 점은 클래스형 컴포넌트에서는 setState를 하면 병합되지만 함수형 컴포넌트에서는 이전 상탯값을 지웁니다.
따라서 다른 상탯값들이 지워지지 않도록, 펼침연산자(Spread Syntax)를 이용해 명시적으로 ...state를 사용해 펼쳐 넣어줘야 합니다.

  • 사용예)

import React, { useState } from 'react'

export default function Profile () {
    const [state,setState] = useState({name:'',age:0})
    return (
        <div>
            <p>{`name is ${state.name}`}</p>
            <p>{`age is ${state.age}`}</p>
            <input type='text' value={state.name} 
            onChange={e=>setState({...state,name:e.target.value})}/>
            <input type='text' value={state.age} 
            onChange={e=>setState({...state,age:e.target.value})}/>
        </div>
    )
}

2. useEffect

(참고 : 리액트 공식문서)

- 개념 :

컴포넌트가 렌더링 될 때마다 특정 작업을 실행할 수 있도록 하는 Hook

- 설명 :

useEffect 는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정 할 수 있는 Hook 입니다. 클래스형 컴포넌트의 componentDidMount 와 componentDidUpdate 를 합친 형태로 보아도 무방합니다.
특정 작업이란 어떤 Effect를 발생시키는 것을 의미하며, 여기서 말하는 effect는 명령형함수 또는 타이머, 로깅, 변형, side Effect 등을 발생시키는 함수등을 말합니다.
즉, 기존의 클래스형 컴포넌트에서 사용할 수 있었던 라이프사이클(생명주기 메소드) 훅(componentDidMount, componentDidUpdate, componentWillUnmount)을 함수형 컴포넌트에서도 side Effect등을 통해 사용할 수 있게 되었습니다. (라이프사이클훅을 대체)

(참고로 상태관리란 component가 mount, unmount, update 됐을 때 각각 특정 작업을 처리하는 것을 의미하며,

컴포넌트가 마운트 됐을 때 (처음 나타났을 때), 언마운트 됐을 때 (사라질 때), 그리고 업데이트 될 때 (특정 props가 바뀔 때) 처리할 수 있는 방법을 살펴보자.
( 최대한 간단하게 알아보고자 하며, 자세한 내용은 공식 자습서를 참고 하면 될것 같다. )

- 기본 구조 :

- 사용법 :

- 사용예 1)

코드를 입력하세요

profile
오늘의 노력은 내일의 오늘입니다.

0개의 댓글