COCO World

[React/리액트] React Hooks - useState / useEffect / useRef / useContext 본문

Front-End/React

[React/리액트] React Hooks - useState / useEffect / useRef / useContext

코코월드주인장 2023. 2. 16. 18:52

1. React Hooks

 리액트 hook은 React 16.8버전에 새로 추가된 기능으로, 함수형 컴포넌트에서 react state와 생명주기 기능(lifecycle features)을 '연동(hook into)'할 수 있게 해준다.  hook은 Class안에서 동작하지 않는데, useState를 예시를 들면 class를 사용하지 않고도 상태를 가질 수 있게 된 것이다.

  • 이전에 리액트가 겪던 문제들을 해결해주며, 클래스형 컴포넌트를 사용하지 않고도 함수형 컴포넌트에서 상태값 접근과 자식 요소에 접근이 가능해 졌다
  • 리액트는 useState, useEffect 같은 내장 Hook을 몇 가지 제공한다
  • 또한 props, state, context, refs 그리고 lifecycle과 같은 리액트 개념에 좀 더 직관적인 API를 제공한다
  • 컴포넌트 간에 상태 관련 로직을 재사용하기 위해 hook을 직접 만드는 것도 가능하다

 

2. useState 

useState는 가장 기본적인 Hook이며, 함수 컴포넌트에서 가변적인 상태를 가지게 해주며, state를 변수로 사용하고, setState를

 이용해서 state값을 수정할 수 있다.

const [state, setState] = useState(initialState);

 

사용할 때에는 해당 임포넌트에서 import 하고 사용한다.

import React, { useEffect } from 'react';

 

함수형 업데이트

setState의 () 안에 수정할 값이 아니라, 함수를 넣는 것이다.

// 현재 number의 값을 가져와서 그 값에 +1을 더하여 반환한 것 입니다.
setState((currentNumber)=>{ return currentNumber + 1 });

 

함수형 업데이트 vs 일반 업데이트 방식의 차이점

 (1) 일반 업데이트 :

   setState가 각각 실행되는 거이 아니라, 배치(batch)로 처리한다.  배치로 처리한다는 뜻은 명령을 여러번 내려도 리액트는

   그 명령   을 하나로 모아 최종적으로 한번만 실행시키는 것이다.

 (2) 함수형 업데이트 :

  setState를 3번 동시에 명령을 내리면, 그 명령을 모아 순차적으로 각각 한번씩 실행시킨다. 순차적으로 리턴된 값으로

   이어받아 명령을 실행한다.

 (3) 리액트가 배치 업데이트를 동작하는 이유?

   리액트는 성능을 위해 setState()를 단일 업데이트(batch update)로 한꺼번에 처리할 수 있다

   이는 불필요한 리렌더링을 방지하기 위함이다 ( = 렌더링 최적화 )

// 기존에 우리가 사용하던 방식
setState(number + 1);

// 함수형 업데이트 
setState(() => {});

 

정리

  • useState의 업데이트 방식은 2가지가 있다 -> 함수형 업데이트, 기본 업데이트(배치)
  • useState로 원시 데이터가 아닌 데이터를 변경할 때는 불변성을 유지해야 한다

 

3. useEffect

useEffect는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다.

쉽게 말해 아래와 같은 상황에서 사용한다.

  • 어떤 컴포넌트가 화면에 보여졌을 때 내가 무언가를 실행하고 싶은 경우
  • 어떤 컴포넌트가 화면에서 사라졌을 때 무언가를 실행하고 싶은 경우

사용할 때에는 해당 컴포넌트 페이지에서 import 하고 사용한다.

import React, { useEffect } from 'react';

 

의존성 배열

'이 배열에 값을 넣으면 그 값이 바뀔 때에만 useEffect를 실행할게'라는 의도로 사용한다.

  • 의존성 배열이 빈 배열([])인 경우 : useEffect는 처음에 딱 한번 실행되고 그 이후에는 실행되지 않는다
  • 의존성 배열에 [value]가 있는 경우: value의 상태값이 바뀔 때 마다 실행된다
// useEffect의 두번째 인자가 의존성 배열이 들어가는 곳 입니다.
useEffect(()=>{
	// 실행하고 싶은 함수
}, [의존성배열])

 

정리

  • 컴포넌트가 mount 또는 unmount 됐을 때 실행하고자 하는 함수를 제어할 때 사용하는 Hook이다
  • 의존성 배열을 통해 함수의 실행 조건을 제어할 수 있다
  • useEffect에서 함수를 1번만 실행시키고자 할 때는 의존성 배열을 빈 배열로 둔다

 

4. useRef

DOM 요소에 접근할 수 있도록 하는 React Hook 이다.

HTML과 javascript에서 특정 DOM을 선택하기 위해서 getElementById를 사용하는 것처럼, 리액트에서도 DOM을 선택해야 할 상황이 발생할때 사용한다.

  • 예를 들어, 특정 element의 input 태그가 focusing 해야할 경우에 사용한다 .

사용할 때에는 해당 컴포넌트 페이지에서 import 하고 사용한다.

import React, { useEffect } from 'react';

 

특징

  • 설정된 ref값은 컴포넌트가 계속해서 렌더링 되어도 unmount전까지 값을 유지한다
  • state와 비슷한 역할을 한다. 다만 state는 변화가 일어날 경우 렌더링이 일어나고, 내부변수는 초기화 된다
  • ref에 저장한 값은 렌더링을 일으키지 않고, ref의 값 변화가 일어나도 렌더링으로 인해 내부변수들이 초기화 되는 것을 막을 수 있다
  • 즉, ref는 리렌더링을 발생시키지 않는 값을 저장할 때 사용한다

 

사용예시

 아이디가 10자리 입력되면 자동으로 비밀번호 필드로 이동하도록 코드 작성하기

import { useEffect, useRef, useState } from "react";
import "./App.css";

function App() {
  const idRef = useRef("");
  const pwRef = useRef("");

  const [id, setId] = useState("");

  const onIdChangeHandler = (event) => {
    setId(event.target.value);
  };

  // 렌더링이 될 때
  useEffect(() => {
    idRef.current.focus();
  }, []);

  // 왜 useEffect 안에 놓았을까요?
  useEffect(() => {
    if (id.length >= 10) {
      pwRef.current.focus();
    }
  }, [id]);

  return (
    <>
      <div>
        아이디 :
        <input
          type="text"
          ref={idRef}
          value={id}
          onChange={onIdChangeHandler}
        />
      </div>
      <div>
        비밀번호 : <input type="password" ref={pwRef} />
      </div>
    </>
  );
}

export default App;

 

5. useContext

우리는 props를 사용하여 부모컴포넌트 -> 자식컴포넌트로 데이터를 전달시켜 준다. 이 때 자식으로의 컴포넌트 전달이 깊어질 때 prop drilling 현상이 발생하는데,  이때 등장한 것이 react context API이고, useContext hook을 통해 전역 데이터를 관리한다.

 

사용할 때에는 해당 임포넌트에서 import 하고 사용한다.

import React, { useContext } from 'React';

 

context API 필수 개념

  • createContext : context 생성
  • Consumer : context 변화 감지
  • Provider : context 전달 ( to 하위 컴포넌트 )

주의할 점

useContext를 사용할 때, Provider에서 제공한 value가 달라진다면 useContext를 사용하고 있는 모든 컴포넌트가 리렌더링 된다.

 따라서 value 부분을 항상 신경쓰면서 사용해야 한다.