[React] Hooks

Saemi Min·2023년 1월 12일
0

처음 만난 리액트

목록 보기
8/17
post-thumbnail

Hooks의 개념과 useState, useEffect

Hooks


-> Hooks을 사용하면 Function Component도 Class Component기능을 모두 동일하게 사용할 수 있게 됨.

Hook(갈고리)

: 원래 존재하는 어떤 기능에 갈고리를 거는 것처럼 끼어들어가 같이 수행되는 것을 의미한다
Hook의 이름은 use를 앞에 항상 넣어서 이름을 지음.

useState()

: state를 사용하기 위한 Hook
: 함수 컴포넌트는 state를 제공하지 않기 때문에 클래스 컴포넌트처럼 state를 사용하고 싶으면 hook을 사용함.

이처럼 count를 함수의 변수로 사용하게 되면 재렌더링이 일어나지 않아 화면에 변한 값이 보여지지 않음. -> state를 사용하여 값이 바뀌도록 재렌더링을 해줘야 함. 함수 컴포넌트에는 이 기능이 없기 때문에 useState를 사용하여 state를 선언하고 업데이트를 해야 함.

배열로 리턴하게 되는 데 첫번째 항목은 state로 선언된 변수이며, 두번째 항목은 해당 state에 set함수명이다.

useState을 사용하여 count값을 state로 관리하도록 만든 것이다.
버튼이 눌렸을 때 setCount()함수를 호출하여 count 값을 1증가시키고, 컴포넌트가 재렌더링하면서 화면에 새 count값이 보여지게 된다. (클래스 컴포넌트가 재렌더링 시키는 과정과 동일)

useEffect()

: Side effect를 수행하기 위한 Hook
Side effect = 부작용
리액트에서의 Side effect = 효과, 영향 의미에 더 가까움. ex) 서버에서 데이터를 받아오거나, 수동으로 DOM을 변경하는 작업들을 effect라고 부름
=> 왜냐하면 다른 컴포넌트에 영향을 미칠 수 있으며, 렌더링 중에는 작업이 완료될 수 없기 때문.
렌더링이 끝난 이후에 실행되어야하는 작업들이기 때문
=> 리액트의 함수 컴포넌트에서 Side effect를 실행할 수 있게 해주는 Hook (생명주기의 함수 기능들을 하나로 통합해서 제공)

: 의존성 배열 = 이 이펙트가 의존하고 있는 배열인데 이 배열 내의 값이 하나라도 변경되었을 때 이펙트 함수가 실행된다.

  • 처음 컴포넌트가 렌더링 된 이후와 업데이트 되고 재렌더링 된 이후에 실행된다.

    : 의존성 배열에 빈 배열을 넣음
    이 해당 effect가 props와 state에 의존하지 않는 것이 되므로 여러번 실행되지 않는다.


    : effect는 함수 컴포넌트 안에서 선언되기 때문에 해당 컴포넌트의 props와 state에 접근할 수 있다.
    위 코드에서는 count라는 state에 접근하여 해당 값이 포함된 문자열을 생성해서 사용하는 것을 볼 수 있다.
    -> 그렇다면 ComponentWillUnmount와 동일한 기능은 UseEffect로 어떻게 구현할 수 있는가?
    아래 코드를 봐보자!

    위 코드는 useEffect에서 서버 API를 사용하여 사용자의 상태를 구독하고 있음. 이후 함수를 하나 리턴하는데 해당 함수 안에는 구독을 해제하는 API를 호출하도록 되어있음.
    => useEffect에서 리턴하는 함수는 컴포넌트가 mount 해제, 즉 unmount 될 때 호출된다.
    결과적으로 useEffect의 리턴 함수의 역할은 ComponentWillUnmount와 동일하다
    또한 useEffect Hook은 하나의 컴포넌트에 여러개를 사용할 수 있다.

    위 코드는 두개의 useEffect Hook을 사용하고 있음.
    useState와 useEffect Hook 각각 2개씩 사용하고 있음.

useMemo

: Memoized value를 리턴하는 Hook

  • Memoization = 최적화를 위해 사용하는 개념 (비용이 높은, 즉 연산량이 많이 드는 함수의 호출 결과를 저장해두었다가 같은 입력값으로 함수를 호출하면 새로 함수를 호출하지 않고 이전에 저장해놨던 호출 결과를 바로 반환하는 것) => 시간도 단축되고, 불필요한 연산을 다시 하지 않아도 되어 컴퓨터의 자원을 적게 씀

    -> 컴포넌트가 다시 렌더링될 때마다 연산량이 높은 작업을 반복하는것을 피할 수 있다. 결과적으로 빠른 렌더링 속도를 얻을 수 있음.
    useMemo로 전달된 함수는 렌더링이 일어나는 동안 실행된다는 점 그렇기 때문에 일반적으로 렌더링이 일어나는 동안 실행되서는 안될 작업을 useMemo 함수에 넣으면 안된다.

    : 따라서 useMemo에 의존성 배열을 넣지 않는 것은 아무런 의미가 없다는 것

    : 결국 mount이후에는 값이 변경되지 않는 것
    그래서 mount 시점에만 한번 값을 계산할 필요가 있을 경우에는 이렇게 사용함. 하지만 대부분의 경우에는 useMemo Hook의 의존성 배열에 변수들을 넣고 해당 변수들의 값이 바뀜에 따라 새로 값을 계산할 경우에 사용한다.

useCallback

: useMemo() Hook과 유사하지만 값이 아닌 함수를 반환
: 컴포넌트가 렌더링될 때마다 매번 함수를 새로 정의하는 것이 아니라 의존성 배열의 값이 바뀌는 경우에만 함수를 새로 정의해서 리턴해주는 것이다.

: useMemo 처럼 함수와 의존성 배열을 파라미터로 갖는다.
파라미터를 갖는 이 함수를 콜백이라고 말한다. 의존성 배열에 있는 변수 중 하나라도 변경되면 Memoization된 콜백함수를 반환한다. 의존성 배열에 따라 Memoized 값을 반환한다는 점에서는 useMemo Hook과 완전 동일함.

  • useCallback Hook을 사용하지 않은 경우
    : 부모 컴포넌트가 렌더링이 될 때마다 자식 컴포넌트도 같이 렌더링된다.
  • useCallback Hook을 사용한 경우
    : 의존성 배열에 빈 배열이 들어갔기 때문에 컴포넌트가 처음 마운트 되는 시점에만 정의되고 이후에는 다시 정의되지 않음. 그리하여 불필요하게 재렌더링 안해도 됨

useRef

: Reference를 사용하기 위한 Hook
리액트에서 Reference란 특정 컴포넌트에 접근할 수 있는 객체이다.
useRef Hook은 바로 이 객체를 반환한다.
reference 객체에는 current라는 속성이 있음

: 컴퍼넌트가 마운트 해제 전까지 계속 유지됨.
= 변경 가능한 current라는 속성을 가진 하나의 상자라고 생각하면 됨.

=> useRef() Hook은 내부의 데이터가 변경되었을 때 별도로 알리지 않는다.
DOM 노드의 변화를 알기 위한 기초적인 방법 => Callback ref

  • Callback ref 방식을 사용
    : 자식 컴포넌트가 변경되었을 때 알림을 받을 수 있고 이를 통해 다른 정보들을 업데이트할 수 있다.

Hook의 규칙과 Custom Hook 만들기

Hook의 규칙

  • Hook은 무조건 최상위 레벨에서만 호출해야 한다. (반복문이나 조건문 또는 중첩된 함수들 안에서 Hook을 호출하면 X)
    : Hook은 컴포넌트가 렌더링될 때마다 매번 같은 순서로 호출되어야 한다.

    : name의 값이 빈 문자열이 되면 조건문이 false가 되어 useEffect가 호출되지 않음
    : 조건문의 결과에 따라 호출되는 Hook이 달라지므로 잘못된 Hook이다.

  • 리액트 함수 컴포넌트에서만 Hook을 호출해야한다.
    : 일반적인 자바스크립트에서 호출하면 X

(개발에 도움이 되는 패키지)
: eslint-plugin-react-hooks :eslint의 plugin
= Hook의 규칙에 따라 강제해 주는 플러그인이다.

Custom Hook 만들기

: 여러 컴포넌트에서 반복적으로 사용되는 로직으로 Hook으로 만들어 재사용하기 위함.
Custom Hook을 만들어야하는 상황
: 온라인인 사람은 초록색으로 표시해주고 싶을 때의 상황
: state가 여러번 중복되는 코드인 경우

  • 중복되는 로직을 Custom Hook으로 추출하기
    Custom Hook : 이름이 use로 시작하고 내부에서 다른 Hook을 호출하는 하나의 자바스크립트 함수

    : 중복되는 로직을 useUserStatus라는 Custom Hook으로 추출함.
    : 특정 규칙은 없음. 단순한 함수와 같음.

  • Custom Hook 사용하기

! Custom Hook의 이름은 꼭 use로 시작해야한다.
: 여러 개의 컴포넌트에서 하나의 Custom Hook을 사용할 때 컴포넌트 내부에 있는 모든 state와 effects는 전부 분리되어있다
: 각 Custom Hook 호출에 대해서 분리된 state를 얻게 됨!
: 각 Custom Hook의 호출 또한 완전히 독립적이다.

  • Hook 들 사이에서 데이터를 공유하는 방법

(실습) Hooks 사용해보기

useCounter() Custom Hook 만들기

  • useCounter.jsx

    :useCounter Hook을 사용하면 어떤 함수 컴포넌트에서든지 카운터 기능을 쉽게 사용할 수 있다.

Accommodate 컴포넌트 만들기

: 사람을 수용하는 시설에서 사용한다는 가정하에

  • Accommodate.jsx

  • 결과

    : 2개의 useEffect Hook이 호출됨.

  • (입장 버튼을 누른 경우)

    : 2개의 useEffect Hook이 호출됨.
    : count 값이 1 증가함.
    : 여기서 의존성 배열이 없는 useEffect Hook이 호출된 이유는 컴포넌트가 업데이트 되었기 때문이고, 의존성 배열이 있는 useEffect Hook이 호출된 이유는 count값이 변경되었기 때문이다.

  • (정원이 가득 찰 때까지 입장 버튼을 누른 경우)

    : isFull의 값이 true가 되기 때문에 입장 버튼이 비활성화 되어 더이상 누를 수 없게 되고 빨간색으로 경고 문구가 출력함.
    로그를 보면 count 값이 10이 된 이후에는 더이상 변하지 않기 때문에 count를 의존성 배열로 갖고있는 useEffect Hook은 호출되지 않는 것을 볼 수 있다.

  • (퇴장 시켜 수용인원을 줄이는 경우)

    : 2개의 useEffect Hook이 호출되고, count값이 줄어듬

  • (수용 인원이 0이 될때까지 수용 인원을 줄이는 경우)

    : 0 아래로 내려갈 수 없게 했기 때문에 값이 0이 되면 더이상 useEffect Hook이 호출되지 않음.

실습 코드 - 깃

참고 자료 SOAPLE

profile
I believe in myself.

0개의 댓글