본문 바로가기

Tech/React

프론트 입문 리액트 삽질기 2 - Props, State Hook

반응형

Props, State Hook

지난번 글에서 Create-React-App을 통해 App 이라는 컴포넌트를 만들어 줬습니다.

이제 이 컴포넌트에 입력 상자를 하나 두고, 버튼을 누르면 환영 팝업이 나타나는 페이지를 하나 구성하려고 합니다.

컴포넌트 내부에 변수를 설정하고 넘기는 일련의 과정이 필요하겠죠?

 

일단은 아무런 인자도 받지 않고, 이름도 하드코딩 되어 있는 새로운 컴포넌트인 Greeting을 생성해 봅니다.

function Greeting(){
    return (
        <div>Hello, My name is <b>Sean</b>!</div>
    );
}

export default Greeting;

 

이제 이 Greeting 컴포넌트를 App 컴포넌트 내부에 배치해 봅니다.

import { Fragment } from 'react';
import './App.css';
import Greeting from './Greeting';

function App() {
  return (
    <Fragment>
      <h1>Hello, World!</h1>
      <Greeting/>
    </Fragment>
    );
}

export default App;

 

이 때, JSX 에서는 두 개 이상의 엘리먼트는 하나의 엘리먼트로 감싸져 있어야 합니다. 그래서 div 태그로 감싸주어도 되지만, 단순히 두 개 이상의 엘리먼츠를 감싸기 위해 div 태그를 하나 더 쓰는게 마음에 들진 않았습니다. 따라서 DOM에 별도의 노드를 추가하지 않고 여러 자식을 그룹화하는 데 사용하는 Fragment 태그를 사용하여 두 엘리먼트를 묶어 주었습니다.

 

Fragments – React

A JavaScript library for building user interfaces

ko.reactjs.org

yarn start

 

이제 컴포넌트가 생성될 때 외부에서 이름을 받도록 Greeting 컴포넌트가 props를 인자로 받도록 설정합니다.

이 때 만약 name이 설정되어 있지 않다면 Not Defined를 넣도록 작성해 봅니다.

function Greeting({name="Not Defined"}){
    return (
        <div>Hello, My name is <b>{name}</b>!</div>
    );
}

export default Greeting;

 

저는 Greeting 함수의 인자로 props가 들어가고, 여기에 default parameter를 지정해 주는 방법을 사용했습니다.

Functional Component에 props를 인자로 넘겨줄 때, default 값을 어떻게 설정해 줄 지 찾다가 함수에 대한 defaultProps가 Deprecate될 것이라는 React core team의 트윗git PR을 보았기 때문인데요,

더 자세한 내용은 react rfc #107의 내용을 보셔도 좋을 것 같습니다.

 

RFC: createElement changes and surrounding deprecations by sebmarkbage · Pull Request #107 · reactjs/rfcs

This proposal simplifies how React.createElement works and ultimately lets us remove the need for forwardRef. Deprecate "module pattern" components. Deprecate defaultProps on function co...

github.com

name으로 "Not Defined"를 기본값으로 갖는 Greeting 컴포넌트는 App.js를 수정하지 않았기 때문에 다음과 같이 동작합니다.

Not Defined

이제 App.js를 다음과 같이 수정한 다음, save를 해 동작을 확인합니다.

import { Fragment } from 'react';
import './App.css';
import Greeting from './Greeting';

function App() {
  return (
    <Fragment>
      <h1>Hello, World!</h1>
      <Greeting name="Sean"/>
    </Fragment>
    );
}

export default App;

Greeting to Sean

이제 App.js에 작은 텍스트 입력 필드를 하나 생성하고 버튼을 만들어 봅니다.

import { Fragment } from 'react';
import './App.css';
import Greeting from './Greeting';

function App() {
  return (
    <Fragment>
      <h1>Hello, World!</h1>
      <div>
        <input type="text" placeholder="Input name"/>
        <button>Ok</button>
      </div>
      <Greeting name="Sean"/>
    </Fragment>
    );
}

export default App;

Small input box

이제 이 입력 상자에 입력된 내용에 따라 아래 컴포넌트의 내용이 바뀌도록 하고 싶습니다.

그러려면 컴포넌트 내부에 변수를 관리하고 있어야겠죠?

기존 클래스 컴포넌트에서는 State를 this.state 형식으로 불러와 사용했는데, 함수형 컴포넌트에서는 hook을 사용합니다.

 

Hook의 개요 – React

A JavaScript library for building user interfaces

ko.reactjs.org

import { useState, Fragment } from 'react';
import './App.css';
import Greeting from './Greeting';

function App() {
  const [value, setValue] = useState('');
  return (
    <Fragment>
      <h1>Hello, World!</h1>
      <div>
        <input type="text" placeholder="Input name"
               onChange={e => setValue(e.target.value)}/>
        <button onClick={() => alert("Welcome,"+value)}>Ok</button>
      </div>
      <Greeting name={value}/>
    </Fragment>
    );
}

export default App;

 

function App() 안을 한줄한줄 살펴보면, 가장 눈에 띄는 부분이 있습니다.

  const [value, setValue] = useState('');

 

저 destructuring 문법은 state hook을 사용하기 위해 사용되었습니다.

실제로 useState 함수를 좀 살펴보면,

    /**
     * Returns a stateful value, and a function to update it.
     *
     * @version 16.8.0
     * @see https://reactjs.org/docs/hooks-reference.html#usestate
     */
    function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];

 

초기값을 인자로 받고 Stateful Value와 해당 Value를 업데이트하기 위한 Function을 반환합니다.

따라서 위 state hook에서 value는 stateful한 값이며, setValue는 해당 값을 업데이트하기 위한 함수입니다.

 

다음,선언해 준 input에서 onChange 이벤트가 발생할 때, 이 setValue 함수를 호출해 줍니다.

        <input type="text" placeholder="Input name"
               onChange={e => setValue(e.target.value)}/>

 

입력박스에 abc가 입력되면 value state가 abc로 변화하고, 이 변화한 값은 다른 컴포넌트인 Greeting으로 흘러갑니다.

      <Greeting name={value}/>

 

그리고 버튼을 클릭하게 되면 JavaScript의 alert 함수가 호출되어 팝업이 등장합니다.

welcone, SEAN!

 

반응형