[리액트] 헷갈렸던 개념들 정리하기 - Hook(useState, useEffect), 상태 관리, 생명 주기

조재현·2022년 12월 6일
0

🎈개요

리액트만의 특별한 개념, hook, 상태관리, 생명주기(Life Cycle) 에 대한 이해가 조금 부족한 것 같아서, useEffect와 useState를 공부하면서 해당 개념도 같이 이번 기회에 정리하고자 한다.


🎈상태 관리란?

보통 유저들의 정보는 서버의 데이터베이스에 저장된다. 예를 들어, 유저의 아이디나, 비밀번호, 비밀번호를 찾기 위한 질문/답에 관한 정보는 서버의 데이터베이스에 저장되어 있다. 이런 정보들은 보통 클라이언트(프론트엔드) - 서버(백엔드) - 데이터베이스의 과정을 거쳐 전달된다.

그러나 확인 버튼을 누르기 전 댓글이나, 설문 참여를 누르기 전 버튼 선택과 같은 정보들은 언제든지 바뀔 수 있기에, 이런 정보들까지 클라이언트에서 서버까지 도달하는 과정을 거친다면 몹시 비효율적인 네트워크 비용을 치뤄야 한다.

따라서, 이렇게 임시적으로 저장되어도 무방한 정보들은 클라이언트 단에서 임시적으로 저장하는 것이 더 효율적이다. React에서 state는 바로 이렇게 임시적인 정보를 저장하기 위해 만들어진 것이다.

📢 Prop와 State는 어떻게 다른가?

Props특정 Component상위 Component로부터 내려받은 속성이라면,
State각각의 Component개별적으로 가지는 값이다.

Props는 상위 컴포넌트로부터 내려받은 값이므로 컴포넌트 내부에서 값을 임의로 변경할 수 없다.


🎈리액트의 생명주기(Life Cycle)

  • 리액트의 생명주기는 크게 생성(Mount), 업데이트(Update), 제거(UnMount) 로 구분지을 수 있다.

    생성(Mount): 컴포넌트가 페이지에 나타날 때
    업데이트(Update): 컴포넌트 내부의 값이 업데이트 될 때
    제거(Unmount): 컴포넌트가 페이지에 사라질 때

  • 각 주기는 Render -> Commit의 단계를 밟는다.

    Render:
    1) Component, State, Props를 로드한다.
    2) Rendering
    Commit
    1) 기존의 값을 갖는 Virtual DOM과 업데이트 된 값을 갖는 Virtual DOM값을 서로 비교
    2) 다른 점이 발견된다면 바뀐 부분만 실제 DOM에 업데이트
    3) useEffect 실행


🎈Hooks

이전 함수형 컴포넌트에서는 기존 클래스형 컴포넌트에선 가능했던 상태 관리나, 생명 주기 사용을 못한다는 단점이 존재했다. 그러나 React가 업데이트 되면서 클래스형 컴포넌트에서만 가능했던 기능들을 함수형 컴포넌트에서도 사용할 수 있게 되었다.

useState
useState는 함수형 컴포넌트에서 상태 관리를 할 수 있도록 하는 hook이다.

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>
    )
}
export default Counter

코드 출처

  • useState를 사용할 때는 기본적으로 상태를 넣는 값(여기서는 value)과 상태를 관리하는 함수(여기서는 setValue)를 선언한다. useState의 인수로는 state의 초기 값이 들어간다. 초기 값은 boolean형이 될 수도, 객체가 될 수도 있고, 숫자가 될 수 있는 등 다양하다.

useEffect
useEffect는 함수형 컴포넌트에서 생명 주기(componentDidMount, componentDidUpdate, componentWillUnMount)를 사용할 수 있도록 하는 hook이다.

import { useEffect, useState } 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>
            <>
            <input value={name} onChange ={onChangeName}/>
            <input value={nickname} onChange ={onChangeNickname}/>
            </>
            <div>
            <b>이름 : </b> {name}
            </div>
            <div>
            <b>닉네임 : </b> {nickname}
            </div>
        </div>
    )
}
export default Info;

코드 출처

위 코드 실행시 component가 mount될때 (처음 웹페이지에 등장), component가 update될때 (input을 입력할 때)마다 console.log가 실행되는 모습을 확인 할 수 있다. (각 생명주기의 Commit과정에서 useEffect가 실행되기 때문)

  1. 만일 초기에 Mount될때만 useEffect를 실행하고 싶다면, 두 번째 인자로 빈 배열을 넣어준다.

    useEffect(()=>{
        console.log('렌더링이 완료되었습니다.');
        console.log({
            name, nickname
        })
    }, [])
  • 위 코드는 처음 component가 Mount될 때만 실행되고 다시 실행되지 않는다.
  1. 만일 특정 값이 Update될 때 useEffect를 실행하고 싶다면, 두 번쨰 인자에 해당 값을 배열의 요소로 넣어준다.

    useEffect(()=>{
        console.log('렌더링이 완료되었습니다.');
        console.log({
            name, nickname
        })
    }, [name])
  • 위 코드는 name필드의 값이 변경 될 때만 실행된다.
  1. useEffect에서 리턴을 하는 경우는 리액트 생명주기의 componentWillUnmount와 같은 효과를 낸다.
function startTimer() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setCount(prevCount => prevCount + 1), 1000);
    return () => clearInterval(id);
  }, []);

  return <h1>{count}</h1>;
}
  • 해당 컴포넌트는 의존성 배열(useEffect의 두번째 인자)로 빈 배열을 넣어주었으므로 mount될 때만 한 번 실행된다. setInterval에 의해 타이머가 실행된다. 이때, useEffect의 return에서 clearInterval을 확인 할 수 있는데, 해당 컴포넌트가 unmount되면 timer가 clear된다.

  • Unmount는 특정 동작을 한다기 보단, setInterval, setTimeout과 같은 함수를 써주고 난 후 생성된 특정 라이브러리 인스턴스를 제거하는 역할을 해준다고 생각하면 편하다 (C에서 malloc하고 free하듯이)

profile
꿈이 많은 개발자 지망생

0개의 댓글