: Hook은 함수 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 “연동(hook into)“할 수 있게 해주는 함수다. Hook은 class 안에서는 동작하지 않지만 대신 class 없이 React를 사용할 수 있다.(이미 짜놓은 컴포넌트를 모조리 재작성하는 것은 권장하지 않으니, 새로 작성하는 컴포넌트부터는 Hook을 이용하시면 된다.)
기존 리액트는 복잡한 컴포넌트들은 이해하기 어려웠다. 컴포넌트 사이에서 state와 관련된 로직을 재사용하기 어려웠었다.
그래서 Hook를 사용하면 컴포넌트로부터 상태 관련 로직을 추상화할 수 있습니다. 이것은 독립적인 테스트와 재사용을 쉽게 해준다. Hook는 계층 변화 없이 상태 관련 로직을 재사용할 수 있도록 도와준다. 많은 컴포넌트들에서 Hook을 사용하여 컴포넌트의 상태를 공유하기 쉬워졌다.(리액트 훅이 나온 이유 : 공식문서)
React는 useState 같은 내장 Hook을 몇 가지 제공합니다. ( Hook APIs )
- 반복문이나 중첩된 함수에서 Hook을 실행하면 안된다.(최상위 파일에서 훅을 호출해야한다.)
- 리액트 함수 컴포넌트에서만 Hook을 호출해야한다.
: useState(state hook)은 state를 함수 컴포넌트 안에서 사용할 수 있게 해주는 특별한 함수다. (원래 react에서 state는 class 컴포넌트에서만 사용 가능하다.)
그래서 함수 컴포넌트를 사용하던 중 state를 추가하고 싶을 때, 클래스 컴포넌트로 바꾸지 않고 함수 컴포넌트 안에서 Hook을 이용하여 state를 사용하면 된다.
import React, { useState } from 'react'; function Example() { // "count"라는 새 상태 변수를 선언합니다.(변수명은 사용자 마음대로 바꾸어도 된다.) const [count, setCount] = useState(0); // useState()의 가로안은 초기값(default)이다. return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount((pre) => pre + 1)}> Click me </button> </div> ); }
위의 예저 처럼 import React, { useState } from 'react';
을 사용하여 example 함수 컴포넌트 안에 state를 추가했다. 여기서 useState는 클래스 컴포넌트의 this.setState와 거의 유사하지만, 이전 state와 새로운 state를 합치지 않는다는 차이점이 있다.
: 코드작성법은 아래와 같다.
const [count, setCount] = useState(0);
여기서 구조 분해 할당을 사용하여 첫번째 엘리먼트를 count라고 사용자가 임의로 정의할 수 있다. 예를 들어서 level, fruit등과 같이.
또 useState()
의 가로 안에 들어갈 수 있는 타입은 숫자
, 문자
,객체
,배열
타입이 들어 갈 수 있고, 가로안의 데이터는 초기값이다. (이 초기값은 첫 번째 렌더링에만 딱 한번 사용된다)
예)
const [age, setAge]useState(0) === this.state = { age : 0 } //
하나의 컴포넌트에서 여러개의 State Hook을 사용할 수도 있다.
function ExampleWithManyStates() { // 한 컴포넌트에서 3가지 상태변수 선언하기 const [age, setAge] = useState(28); const [fruit, setFruit] = useState('banana'); const [count, setCount] = useState(0); }
fruit과 setFruit, 총 2개의 값을 만들고 있습니다. 즉, useState를 사용하면 fruit이라는 첫 번째 값과 setFruit라는 두 번째 값을 반환합니다. 아래의 코드와 같은 효과를 낼 수 있습니다.
var fruitStateVariable = useState('banana'); // 두 개의 아이템이 있는 쌍을 반환 var fruit = fruitStateVariable[0]; // 첫 번째 아이템 var setFruit = fruitStateVariable[1]; // 두 번째 아이템
클래스 컴포넌트는 count를 보여주기 위해 this.state.count를 사용해야하지만, Hook을 사용하면 간단하게 변수만 적으면 사용이 가능하다.
let App = () => { const [count, setCount] = useState(0) return ( <p>You clicked {count} times</p> ) } // <p>You clicked {this.state.count} times</p> // 바로 위의 코드는 class에서 this.state를 사용할때 코드다.
클래스 컴포넌트는 count를 갱신하기 위해 this.setState()를 호출한다. Hook에서는 setCount가 그 역할을 대신한다. 예는 아래와 같다.
let App = () => { const [count, setCount] = useState(0) return ( <button onClick={()=> setCount((pre) => pre + 1)}>You clicked {count} times</button> ) }
: React class의 componentDidMount 나 componentDidUpdate, componentWillUnmount와 같은 목적으로 제공되지만, 하나의 API로 통합된 것이다.
아래 예시는 React가 DOM을 업데이트한 뒤에 문서의 타이틀과 'your level is'문구를 바꾸는 컴포넌트다.
import React, { useState, useEffect } from "react"; let App = () => { const [count, setCount] = useState(0); const [level, setLevel] = useState("low"); let levelChange = () => { if (count >= 5) { return setLevel("high"); } else if (count <= 5) { return setLevel("low"); } }; useEffect(() => { // useEffect 사용 levelChange(); document.title = `your level is ${level}`; }); return ( <div className="App"> <div>your level is {level}</div> <h2>{count}</h2> <button className="btn" onClick={() => setCount(count + 1)}> + </button> <button className="btn" onClick={() => setCount(count - 1)}> - </button> </div> ); };
useEffect를 사용하면, React는 DOM을 바꾼 뒤에 'effect' 함수를 실행할 것이다. Effects는 컴포넌트 안에 선언되어있기 때문에 props와 state에 접근할 수 있다. 기본적으로 React는 매 렌더링 이후에 effects를 실행한다.
useState와 마찬가지로 컴포넌트 내에서 여러 개의 effect를 사용할 수 있다.
만약에 effect를 여러번 사용하는경우(componentDidMount, componentDidUpdata를 사용하는경우)에는 순서에 맞게 코드를 적어야한다. effect는 실행 순서대로 작동하기 때문이다.
: 리액트팀에서 useEffect의 두번째인자를 정할수 있게 하였다. 이 두번째 인자는 Array이다.
두번째 인자는 무슨 역할을 하는가 ? 이 배열은 배열의 인자인 스테이트들이 바뀔때마다 componentDidUpdate가 발동 된다는것을 의미한다.
예를 들어서, 두번째 인자에 빈배열을 넣으면 Mount될때만 실행 시키겠다는 의미이고, [count] 를 하게되면 count가 변할때마다 update를 하겠다는 의미가 되겠다.