React | Hooks 01 ( 개요 / state / effect )

Kate Jung·2021년 1월 31일
0

React

목록 보기
2/28
post-thumbnail

1. Intro

1-1. Hooks 란?

  • React에는 4가지의 Built-in Hooks

    1. useState - 기본 & 핵심
    2. useEffect - 기본 & 핵심
    3. useRef
    4. useReducer
  • Hooks란?

    • 함수 컴포넌트에서 React state &생명주기 기능(lifecycle features)“연동(hook into)“ 할 수 있게 해주는 함수

    • class 내부에서 동작x

      → class 없이 React를 사용 가능하게 함

    • Hook을 직접 만드는 것(custom hook)도 가능

      → 컴포넌트 간에 상태 관련 로직을 재사용하기 위해

1-2. 왜 사용?

:: 공식 문서

  • 컴포넌트 사이에서 상태 관련 로직의 재사용 힘듦.
  • 복잡한 컴포넌트 → 이해 힘듦
  • Class: 사람과 기계 혼동 시킴

:: 클래스 → 클로저(Closure)

  • 클래스 문제
    • state가 참조하는 값: 항상 최신이기 때문에 결과가 보장되지 않는다.
      (ex. 인☆그램 follow를 하고 빠르게 다른 사람 follow를 하면 마지막 follow한 사람 것만 알림창이 뜬다.)

⇒ 해결: 함수 컴포넌트에 클로저(state, 라이프사이클 구현)

1-3. 사용 규칙

규칙 1 : 최상위(at the top level)에서만 호출

  • 반복문, 조건문, 중첩된 함수 내 Hook 실행 X
  • 이유
    • 컴포넌트가 렌더링 될 때마다 항상 동일한 순서로 훅이 호출되는 것이 보장
                import React, { useState } from "react"

                function Hooks(props) {
                	if (!props.isExist) {
                		const [state, setState] = useState(); // Error!
                	}
                	const [state2, setState2] = useState(); // Error!
                }

                // react가 여러 훅들을 구분할 수 있는 유일한 정보는 훅이 사용된 순서 뿐이기 때문.

규칙 2 React 함수 컴포넌트 내에서만 Hook 호출

  • 이 외 가능한 곳 : 직접 작성한 custom Hook 내

2. State Hook

2-1. useState

        const [state, setState] = useState(initialState);
  • 최초 렌더링을 하는 동안,
    반환된 state(state) === 첫 번째 전달된 인자(initialState)의 값
  • setState 함수
    • state 갱신 시 사용
    • 새 state 값을 받아 컴포넌트 리렌더링을 큐에 등록
                setState(newState + 1); // setState와 동일하게 비동기 업데이트
                setState(prev => prev + 1);
  • 다음 리렌더링 시에 useState를 통해 반환 받은 첫 번째 값은 항상 갱신된 최신 state

2-2. Tips

  • 우선, 사용법 숙지
    - (기존 setState와 마찬가지로) 비동기 update
    - useState 실행 시 state, setState 한 쌍이 부여됨

  • 기억해 둘 개념

    • 가비지 컬렉팅
      - 함수는 실행이 완료되면 함수 내에서 사용했던 모든 메모리들을 정리
      - 더 이상 참조하는 곳이 없는 메모리에 대해서 실행
    • 클로저
      - 함수 실행이 끝나고도 메모리에 스스로를 남겨둘 수 있는 방법
      - 자신이 생성될 시점의 환경을 기억하는 함수
                // 아주 간단한 버전의 useState

                const useState = (init = undefined) => {
                  let value = init

                  const getter = () => value // 클로저
                  const setter = next => (value = next) // 클로저

                  return [getter, setter]
                }

                const [state, setState] = useState('클로저')

                state()
                setState("어려워!")
                state()

2-3. FAQ

  • useState()는 상태 분할 관리가 좋다

    • 함께 변경되는 것에 따라 분할하는 것이 좋다.
  • 어떻게 useState 는 상태값 저장하나?

    • 함수는 상태 저장 x

    • 클로저가 출동한다면?
      - 함수형 컴포넌트: 상태 관리 가능(Hooks 사용→ state 저장 시, useState()사용)

      • useState()
        • 함수
        • 변수 저장(클로저 이용)
        • 예시
                    const useState = (init = undefined) => {
                      let value = init

                      const getter = () => value // 클로저
                      const setter = next => (value = next) // 클로저

                      return [getter, setter]
                    }

                    const [state, setState] = useState('클로저')
		- 두 함수 (`getter()`, `setter()` ): 배열 형태로 리턴
                - `useState`사용 시, 배열 구조분해 할당 형태 사용 다수

                → 일반적인 함수

                실행 종료(return)되고 나서 내부의 데이터들이 가비지 컬렉팅 되어야 됨

                → 이 경우

                내부 함수: 지역 변수 참조 → 안 사라짐

                외부로 노출된 getter, setter 함수를 통해 내부 변수에 지속적으로 접근하며 호출/재할당 가능
  • setState 비동기 처리(두 번째 인자) 방법
            // class component
            handleBtnColor = () => {
            	this.setState({
            		color: "red"
            	}, () => console.log(this.state.color))
            }
            // function component
            const [color, setColor] = useState("blue")

            const handleBtnColor = () => {
            	setColor("red")
            }

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

3. Effect Hook

3-1. useEffect

  • componentDidMount/ componentDidUpdate/ componentWillUnmount와 같은 목적 + 하나의 API로 통합
        useEffect(function);

        useEffect(() => {}, [count]) // 의존성 배열 (배열 안에 담긴 값들을 추적, 그때 마다 업데이트)
  • 인자: 명령형 or 어떤 effect를 발생하는 함수

  • (useEffect에 전달된) 함수 수행 시기
    - 화면에 렌더링이 완료된 후 수행
    - 기본적으로 동작: 모든 렌더링 완료 후에 수행
    - 어떤 값이 변경되었을 때만 실행 되게 할 수 있음

  • 사용법

            useEffect(() => {
            	console.log("componentDidUpdate")
            })

            useEffect(() => {
            	console.log("componentDidMount")
            	return () => console.log("componentWillUnmount")
            }, [])

            useEffect(() => {
            	console.log("componentDidMount")
            	console.log("componentDidUpdate") // + shouldComponentUpdate
            	return () => console.log("componentWillUnmount")
            }, [state])

            // WRONG!!
            useEffect(() => {
            	console.log("CDM 쓰고 싶어요")
            }, [])

            useEffect(() => {
            	console.log("CDU 쓰고 싶어요")
            }, [state])

3-2. FAQ

  • 서로 관련 없는 로직들: 여러 useEffect 사용 해서 갈라 놓기

  • useEffect 역할

    • 컴포넌트가 렌더링 이후에 어떤 일을 수행 해야 하는 지 알려줌

      → 우리가 넘긴 함수를 기억했다가(이 함수를 ‘effect’라고 부릅니다) DOM 업데이트를 수행한 이후에 불러낼 것

      • 이 경우, effect를 통해 문서 타이틀 지정, 데이터 가져오기, 다른 명령형(imperative) API 부르기 등 가능
  • useEffect는 렌더링 후 매번 수행 (수정 가능)

    • 렌더링 이후에 발생하는 것으로 생각하라

    • effect가 수행되는 시점

      이미 DOM이 업데이트되었음을 보장

    • 기본: 첫번째 렌더링과 이후 모든 업데이트에서 수행

      effect를 필요에 맞게 수정하는 방법)

useEffect Advanced

  • useEffect vs 라이프 사이클

    useEffect: 여러가지 라이프 사이클이 합쳐진 형태

    • componentDidMount (의존성 배열 : [])
    • shouldComponentUpdate (의존성 배열 내에 해당 사항 없을 경우)
    • componentDidUpdate (의존성 배열 자체가 없거나, 해당 사항이 있을 경우)
    • componentWillUnmount
  • Render → Effect Callback → Clean Up!

            const Foo = () => {
              const [state, setState] = useState(0);

              console.log("render", state);

              useEffect(() => {
                console.log("useEffect Callback", state);
                return () => console.log("cleanUp", state);
              }, [state]);

              return <div onClick={() => setState(state + 1)}>하잉</div>;
            };

            export default Foo;
- 함수 body ⇒ `render`
- useEffect
   - 의존성 배열 : useEffect 내부에서 해당 값의 변화만(!) 감지
   - 클린업 함수 : 구독/해제 등 다음 effect 전에 이번 effect의 내용을 정리해야 할 때 사용
  • 실제 동작
            render, 0
            useEffect Callback, 0
            // 클릭
            render, 1
            cleanUp, 0
            useEffect Callback, 1
  • 클린업 함수가 (다음 번 render 보다) 먼저 실행하는 이유
    • 렌더 완료 후 → effect 실행
    • 더 나은 ux 제공
    • effect 실행 시점에 렌더 완료 보장 가능
  • 클린업 함수 값: 예전 사이클 값 가져오는 이유
    • 클린업 함수가 클로저("자신이 생성될 시점의 환경을 기억하는 함수")로서 생성될 시점: 이전 렌더 때, 즉 이전 환경을 기억함.
profile
복습 목적 블로그 입니다.

0개의 댓글