React 공식문서 해석하며 공부하기 : Using the State Hook

배지로·2021년 9월 6일
0
post-thumbnail

해석하며 공부하는 것을 목적으로 하기 때문에 다수의 의역, 오역이 있음을 미리 밝힙니다.
원본 : https://reactjs.org/docs/hooks-state.html

State Hook 사용하기

Hooks는 리액트 16.8 버전에 새롭게 추가되었습니다. 이로 인해 클래스를 사용하지 않고도 state나 다른 리액트 기능들을 사용할 수 있게 되었죠.

소개 페이지에서 Hooks에 익숙해지기 위한 예시를 사용한 바 있습니다:

import React, {useState} from 'react';

function Example(){
  //count라는 이름의 새로운 state 변수를 선언
  const [count, setCount]=useState(0);
  
  return(
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()=>setCount(count+1)}>
        Click me
      </button>
    </div>
  );
}

위의 코드를 동일한 기능을 하는 클래스 예시와 비교하면서 Hooks를 배워봅시다!


동일한 기능의 클래스 예제

이전에 리액트에서 클래스를 사용해본 적이 있으시다면, 이 코드는 친숙할겁니다:

class Example extends React.Component{
  constructor(props){
    super(props);
    this.state={
      count:0
    };
  }
  
  render(){
    return(
      <div>
      <p>You clicked {count} times</p>
      <button onClick={()=>this.setStates({count:this.state.count+1})}>
        Click me
      </button>
    </div>
    );
  }
}

{count:0}로 state를 시작하고, 사용자가 버튼을 클릭할 때 this.setState()가 호출되면서 state.count가 증가합니다. 이 페이지에서 클래스에서 사용하는 snippet을 사용할 것입니다.

참고
더 현실적인 예시가 아니라 counter를 예시로 드는지 궁금하실 수 있습니다. 이 예시는 Hooks에 여전히 익숙하지 않은 우리지만 API에도 집중할 수 있게 도와줍니다.


Hooks와 함수 컴포넌트

리액트의 함수 컴포넌트의 기본적인 모양은 아래와 같음을 상기시키고 지나갑시다:

const Example=(props)=>{
  //여기서 Hooks를 사용할 수 있습니다!
  return <div/>;
}

또는 이런 모양도 가능합니다:

function Example(props){
  //여기서 Hooks를 사용할 수 있습니다!
  return <div/>;
}

이것을 "state가 없는 컴포넌트"라고 부른다는 것은 이미 알고 계실 겁니다. 이제 여기서도 리액트 state를 쓸 수 있는 방법을 알려드릴 예정이므로 "함수 컴포넌트"라고 불러도 됩니다.

Hooks는 클래스 안에서 작동하지 않습니다. 하지만 클래스를 작성하지 않고도 Hooks를 작성할 수 있습니다.


Hooks가 뭔가요?

우리의 새로운 예시는 리액트의 useState를 불러와서 시작해봅시다:

import React, { useState } from 'react;

function Example(){
  // ...
}

Hook이 무엇인가요? Hook은 리액트 기능에 "연결시켜주는" 특별한 함수입니다. 예를 들어, useState는 함수 컴포넌트에 리액트 state를 추가할 수 있게 해주는 Hook이죠. 다른 Hooks은 추후에 배워봅시다.

Hook을 언제 사용하면 될까요? 함수 컴포넌트를 작성하고 state를 추가해야겠다고 생각이 들면, 예전에는 함수 컴포넌트를 클래스 컴포넌트로 변환해야 했습니다. 이제는 존재하는 함수 컴포넌트에 Hook를 사용하면 됩니다. 이제 그렇게 해볼 거에요!

참고:
컴포넌트 내의 어디에서 Hook를 사용할 수 있는지, 혹은 없는지에 대한 특별한 규칙들이 있습니다. 그 규칙들에 대해서는 Hooks의 규칙 문서에서 배울 예정입니다.


State 변수 선언하기

클래스에서는, 생성자 안에서 this.state{count:0}으로 세팅해서 count state를 0으로 초기화했었죠:

class Example extends React.Component{
  constructor(props){
    super(props);
    this.state={
      count:0
    };
  }

함수 컴포넌트에서는, this를 사용하지 않기 때문에 this.state를 할당하거나 읽지 못합니다. 대신에 컴포넌트 안에서 useState Hook을 직접 호출하죠:

import React, { useState } from 'react';

function Example(){
  //count라는 이름의 새로운 state 변수를 선언
  const [count,setCount]=useState(0);

useState 호출이 하는 일이 뭔가요? "state 변수"를 선언해줍니다. count라고 이름 붙여졌지만, 다른 어떤 것으로도 이름 붙일 수 있습니다. banana도 됩니다. 이것이 함수 호출 사이에서 값들을 "보존"하는 방법입니다. - useState는 클래스에서 this.state가 수행하던 기능과 정확히 같은 기능을 하는 새로운 방법입니다. 일반적으로, 변수는 "사라지지만" state 변수는 리액트에 의해 보존됩니다.

useState에 인수로 어떤 것을 전달하나요? useState() Hook의 유일한 인수는 state의 초기값입니다. 클래스와 다르게, state는 객체일 필요는 없습니다. 필요한 것이 숫자나 문자열이라면, 그것만 가지고 있는 것도 가능합니다. 예시에서, 사용자가 몇 번을 클릭했는지만을 알기를 원한다면, 초기값으로 0을 전달하면 됩니다. (state로서 두 가지 다른 값을 저장하고 싶다면, useState()를 두 번 호출하면 됩니다)

useState는 무엇을 반환하나요? useState는 한 쌍의 값을 반환합니다: 현재 state와 state를 업데이트한 함수. 이것이 const [count,setCount]=useState()를 작성하는 이유입니다. 클래스의 this.state.countthis.state와 유사하지만 함수에서는 쌍으로 반환받을 수 있다는 것이 다르죠. 사용하는 문법에 친숙하지 않다면, 이 페이지의 마지막 부분에서 다시 한 번 살펴보겠습니다.

이제 우리는 useState Hook이 무엇을 하는지에 대해서 알게 되었고, 예시가 더 잘 이해될 거에요:

import React, { useState } from 'react';

function Example() {
  //count라는 이름의 새로운 state 변수를 선언
  const [count, setCount] = useState(0);

count라는 이름의 state 변수를 선언했고, 그것을 0으로 설정했습니다. 리액트는 다시 렌더링하기 전까지 이 값을 기억하고, 함수에 가장 최신의 정보를 제공할 것입니다. 현재 count를 업데이트하길 원한다면, setCount를 호출하면 됩니다.

참고
createState가 아니라 useState로 이름 짓게 되었을까요? 이것이 궁금하실 수 있습니다.
컴포넌트의 처음의 렌더링에서만 state가 만들어지는 것이기 때문에 "Create"는 정확한 표현이 아닙니다. 다음 렌더링에서는, useState가 현재의 state를 제공합니다. 매번 새롭게 만들어지면 "state"가 아니겠죠! Hook 이름들이 항상 use로 시작하는 또 다른 이유는 Hooks의 규칙 문서에서 배워보도록 합시다!


State 가져오기

클래스에서 현재 count를 보여주고 싶다면 this.state.count를 불러옵니다:

<p>You clicked {this.state.count} times </p>

함수에서는 직접 count를 사용해서 불러옵니다

<p>You clicked {count} times </p>

State 업데이트하기

클래스에서는, count state를 업데이트하기 위해서는 this.setState()를 불러와야 했습니다:

<button onClick={()=>this.setState({count:this.state.count+1})}>
  Click me
</button>

함수에서는, setCount와 변수 count를 가지고 있기 때문에, this를 사용할 필요가 없습니다:

<button onClick={()=>setCount(count+1)}>
  Click me
</button>

요약

이제는 우리가 배운 것들을 한 줄씩 요약하면서 얼마나 이해했는지 체크해봅시다.

 1:  import React, { useState } from 'react';
 2:
 3:  function Example() {
 4:    const [count, setCount] = useState(0);
 5:
 6:    return (
 7:      <div>
 8:        <p>You clicked {count} times</p>
 9:        <button onClick={() => setCount(count + 1)}>
10:         Click me
11:        </button>
12:      </div>
13:    );
14:  }
  • 첫번째 줄: 리액트에서 useState Hook을 불러옵니다. 이것은 함수 컴포넌트 내에서 state를 사용할 수 있게 합니다.
  • 네번째 줄: Example 컴포넌트 안에 useState Hook을 호출하여 새로운 state 변수를 선언합니다. useState Hook은 변수 쌍들을 부여한 이름으로 지정하고 반환합니다. 첫번째 변수는 버튼 클릭 횟수를 저장하는 변수이기 때문에 count라고 이름붙였습니다. useState의 유일한 인수로 0을 전달함으로서 count 변수를 0으로 초기화했습니다. useState의 두번째 반환 값은 함수입니다. 이 함수는 count를 업데이트되게 하기 때문에 setCount라고 이름붙였습니다.
  • 아홉번째 줄: 사용자가 클릭을 할 때, setCount을 호출하여 state 변수를 갱신합니다. 리액트는 Example 컴포넌트를 다시 렌더링하고 새로운 count값을 컴포넌트에 전달합니다.

처음치고 너무 많은 것을 배운다고 생각할 수 있습니다. 서두르지 마십시오! 설명에서 놓친 것이 있으시다면, 위의 코드를 다시 보고 처음부터 다시 천천히 읽어보세요. 클래스에서 state가 어떻게 동작하는지 "잊고", 새로운 눈으로 코드를 본다면 이해가 될 것입니다.

Tip : 대괄호가 의미하는 것은 무엇일까요?

state 변수를 선언할 때 대괄호를 이용하는 것을 눈치채셨을 겁니다:

const [count, setCount]=useState(0);

왼쪽의 state 변수는 리액트 API의 일부분이 아니므로 원하는대로 이름붙일 수 있습니다:

const [fruit, setFruit]=useState('banana');

이것은 자바스크립트 문법에서 "배열 구조 분해"라고 부릅니다. 이것은 fruit, setFruit이라는 새로운 변수를 만들게 되면, fruit은 useState에 의해 반환되는 첫번째 항목이고 setFruit는 두번째 항목이라는 것을 의미합니다. 아래 코드가 동일한 기능을 합니다:

var fruitStateVariable=useState('banana'); // 쌍으로 반환
var fruit=fruitStateVariable[0]; //쌍으로 반환되는 것 중에 첫번째 항목
var setFruit=fruitStateVariable[1]; //쌍으로 반환되는 것 중에 두번째 항목

useState를 사용하여 state 변수를 선언할 때, 두 항목을 저장하고 있는 배열로, 즉 쌍으로 반환됩니다. 첫번째 항목은 현재 값을, 두번째 항목은 첫번째 항목을 업데이트할 수 있는 함수입니다. 각 항목이 특정한 의미를 가지고 있기 때문에 항목들에 접근하는데 [0][1]을 사용하는 것은 혼란을 야기할 수 있습니다. 이것이 배열 구조 분해를 사용하는 이유입니다.

참고
리액트로 다시this와 같은 것들이 전달되지 않기 때문에 어떤 컴포넌트의 useState인지 리액트가 어떻게 아는지에 대해서 궁금하실 수 있습니다. 이 질문의 답과 많은 다른 질문들은 FAQ 섹션에서 다루도록 하겠습니다.

Tip : 여러 가지 State 변수 사용하기

한 개 이상의 state를 사용하고 싶으면 다른 state 변수에 다른 이름을 지어주면 되기 때문에 state 변수를 [something,setSomething]의 쌍으로 선언하는 것은 편리하기도 합니다:

function ExampleWithManyStates(){
  //여러개의 state 변수 선언!
  const [age,setAge]=useState(42);
  const [fruit,setFruit]=useState('banana');
  const [todos,setTodos]=useState([{text:'Learn Hooks'}]);

위의 컴포넌트에서 age,fruit,todos를 지역 변수로 가지고 있고, 이 변수들을 개별적으로 업데이트할 수 있습니다:

function handleOrangeClick(){
  //this.setState({fruit:'orange'})와 비슷합니다
  setFruit('orange');
}

많은 state 변수를 사용할 필요 없습니다. State 변수는 객체와 배열을 가지고 있어도 되기 때문에 관련된 데이터들을 함께 그룹짓는 것도 여전히 가능합니다. 그러나, 클래스의 this.setState와 다르게, state 변수를 업데이트하는 것은 변수들을 합치는 것이 아니라 대체하는 것입니다.

독립적인 state 변수들을 쪼개는 것에 대한 권장사항은 FAQ 페이지에서 제공해드리겠습니다.


다음 단계

이 페이지에서는 리액트에서 제공하는 Hook 중에 하나인 useState를 배워보았습니다. 우리는 때때로 useState를 "State Hook"이라고 부르기도 합니다. 그것은 리액트 함수 컴포넌트에 지역 state를 더하게 도와줍니다.

우리는 Hooks가 무엇인지에 대해서 조금이나마 배웠습니다. Hooks는 리액트 기능들을 함수 컴포넌트에 연결시켜주는 함수입니다. Hooks의 이름은 언제나 use로 시작하며, Hooks에 대해서 경험하지 못한 것이 여전히 많습니다.

이제, 다음 Hook, useState에 대해서 배워봅시다. useState는 컴포넌트에서 side effect를 일으키게 하고 클래스의 생명주기 메소드와 비슷합니다.

profile
웹 프론트엔드 새싹🌱

0개의 댓글