본문 바로가기
Programming 개발은 구글로/Web[프론트엔드&백엔드]

[Web] React Hooks - useState, useEffect 등

by 40대직장인 2022. 6. 29.

React Hooks

: React v16.8에 새로 도입된 기능입니다.

  • useState: 함수형 컴포넌트에서도 상태 관리
  • useEffect: 렌더링 직후 작업을 설정
  • useContext: Context 쉽게 사용하기 위해 사용
  • useReducer: 컴포넌트에서 다양한 상태에 따라 다른 값으로 업데이트

1. useState

: 함수형 컴포넌트에서도 가변적인 상태로 상태를 관리하는 경우 사용이 됩니다.

 

React 개념 설명했듯이 Html 값을 변화시키려면 새로고침을 해야 하는데, 전체 화면을 새로고침하는 것은 비효율적입니다. 그래서 변경된 화면만 새로고침하기 위해 useState를 사용합니다. 

 

 

 

참고 글 : [Web] 프론트엔드 React 개념

2022.06.23 - [Programming Web[프론트엔드 & 백엔드]] - [Web] 프론트엔드 React 개념

 

 

state와 Lifecycle을 사용할 때 class를 사용합니다. 
Hook이 없었던 시절에는 함수형 컴포넌트에서 state와 lifecycle 관리를 못 했지만, 지금은 함수형 컴포넌트에서 Hook()을 사용하여 useState, useEffect을 활용하여 state와 Lifecycle 관리가 가능합니다.



참고 글: [Web] React state & setState 개념 이해

2022.06.27 - [Programming Web[프론트엔드 & 백엔드]] - [Web] React state & setState 개념 이해

 

 

 

< 예제 코드 Info.js>

import React, { Fragment, useState } from 'react'; // useState를 사용하기 위해 import

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 (
    <Fragment>
      <div>
        <input value={name} onChange={onChangeName} />
        <input value={nickname} onChange={onChangeNickname} />
      </div>
      <div>
        <div>
          <b>이름:</b> {name}
        </div>
        <div>
          <b>닉네임: </b>
          {nickname}
        </div>
      </div>
    </Fragment>
  );
};

export default Info;

 

 

아래와 같이 비구조화 할당 문법을 사용합니다.

  const [name, setName] = useState('');

 

위의 코드에서 배열의 첫 번째 원소는 상태 값이고, 두 번째 원소는 상태를 설정하는 함수입니다.

이 함수에 Parameter를 넣어서 호출하게 되면 전달받은 Parameter로 값이 바뀌게 되고 컴포넌트는 정상적으로 리렌더링 됩니다.

 

 

 

2. useEffect

: React 컴포넌트가 랜더링 될 때마다 특정 작업을 수행하도록 설정하는 경우 사용이 됩니다.

 

※ 클래스 컴포넌트의 componentDidMount와 componentDidUpdate를 합친 기능과 비슷합니다.

 

< 예제 코드 Info.js>

import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    console.log("렌더링이 완료되었습니다!");
    console.log({
      name,
      nickname
    });
  });

  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;

 

 

2.1 마운트가 될 때만 실행

: useEffect에서 설정한 함수를 컴포넌트가 화면에 가장 처음 렌더링 될 때만 실행되고 업데이트할 경우에는 실행할 필요가 없는 경우엔 함수의 두 번째 Parameter로 비어있는 배열을 넣어주시면 됩니다.

  useEffect(() => {
    console.log('마운트 될 때만 실행됩니다.');
  }, []);

 

 

2.2 특정 값이 업데이트가 될 때만 실행

: useEffect 를 사용할 때 특정 값이 변경이 될 때만 호출하게 하고 싶을 경우만 사용합니다.

클래스 컴포넌트의 경우 아래와 같이 작성됩니다.

componentDidUpdate(prevProps, prevState) {
  if (prevProps.value !== this.props.value) {
    doSomething();  
  }
}

props 안 value 값이 변경되는 경우에만 특정 작업(doSomething())을 수행합니다.

 

아래와 같이 useEffect 부분만 변경을 했습니다.

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

 

 

 

2.3. cleanup API

: 컴포넌트가 언마운트 되기 전이나 업데이트되기 전에 어떠한 작업을 수행하고 싶다면 useEffect에서 cleanup 함수를 반환하면 됩니다.

 

  useEffect(() => {
    console.log('effect');
    console.log(name);
    return () => {
      console.log('cleanup');
      console.log(name);
    };
  });

 

 

 

 

Unmount 될 때만 cleanup 함수를 호출하고 싶다면, useEffect 함수의 2번째 Parameter를 비운 배열로 만드시면 됩니다.

  useEffect(() => {
    console.log('effect');
    console.log(name);
    return () => {
      console.log('cleanup');
      console.log(name);
    };
  }, []);

 

3. useContext

: 함수형 컴포넌트에서 context를 보다 더 쉽게 사용하기 위해서 사용이 됩니다.

 

ContextSample.js

import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('black');
const ContextSample = () => {
  const theme = useContext(ThemeContext);
  const style = {
    width: '24px',
    height: '24px',
    background: theme
  };
  return <div style={style} />;
};

export default ContextSample;

<App.js>

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

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

export default App;

 

 

 

검은색 사각형이 디스플레이가 됩니다.

 

4. useReducer

: useState 보다 컴포넌트에서 더 다양한 상황에 따라 다양한 상태를 다른 값으로 업데이트해주고 싶을 때 사용하는 Hook입니다.

 

리듀서는 현재 상태와 업데이트를 위해 필요한 정보를 담은 액션(action) 값을 전달받아 새로운 상태를 반환하는 함수입니다.

 

리듀서 함수에서 새로운 상태를 만들 때는 꼭 불변성을 지켜주어야 합니다.

function reducer(state, action) {
  return { ... }; // 불변성을 지키면서 업데이트한 새로운 상태를 반환합니다
}

// 액션값은 주로 다음과 같은 형태로 이루어져있습니다.
{
  type: 'INCREMENT',
  // 다른 값들이 필요하다면 추가
}

Redux에서는 액션 객체에는 어떤 액션인지 알려주는 type 필드가 꼭 있어야 하지만, useReducer에서 사용하는 액션 객체는 꼭 type를 지니고 있을 필요가 없습니다. 심지어, 객체가 아니라 문자열이나, 숫자여도 상관이 없습니다.

 

기존의 Counter 코드를 useReducer에 맞게 수정합니다.

import React, { useReducer } from 'react';

function reducer(state, action) {
  // action.type에 따라 다른 작업 수행
  switch (action.type) {
    case 'INCREMENT':
      return { value: state.value + 1 };
    case 'DECREMENT':
      return { value: state.value - 1 };
    default:
      return state; // 아무것도 해당되지 않을 때 기존 상태 반환
  }
}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { value: 0 });

  return (
    <div>
      <p>
        값은 <b>{state.value}</b> 입니다.
      </p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
    </div>
  );
};

export default Counter;

useReducer의 첫 번째 Parameter는 리듀서 함수, 그리고 두 번째 Parameter는 해당 리듀서의 기본 값을 넣어줍니다.

 

이 Hook을 사용했을 때에는 state 값과 dispatch 함수를 받아오게 되는데요, 여기서 state는 현재 가리키고 있는 상태고, dispatch는 액션을 발생시키는 함수입니다.

 

dispatch(action)와 같은 형태로, 함수 안에 Parameter로 액션 값을 넣어주면 Reducer 함수가 호출되는 구조입니다.

 

useReducer를 사용했을 때의 가장 큰 장점은 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있다는 점입니다.

 

useMemo, useCallback, useRef, Custom Hook, usePromise 등은 다음 기회에 정리하도록 하겠습니다.

 


 

참고 글: 리액트의 Hooks 완벽 정복하기, [react web] Hook 기초_useState

https://velog.io/@velopert/react-hooks

 

https://han-py.tistory.com/398

 

 

 

 

댓글