[React.ts] React를 Typescript로 시작해보기 - Props, State

이번 글에서는 Props, State를 Typescript에서 어떻게 사용하는지에 대해 알아보겠습니다.

Javascript에서는 state를 정의하기 위해 생성자를 사용하였고, 해당 생성자의 파라미터로 Props를 넣어주었으며 Props가 필요하다면, 컴포넌트 코드 밑에 Props 타입을 정의했었습니다. 

import React, { Component } from 'react';


class Header extends Component {
    constructor(props) {
    	super(props);
        
        this.state = {
            ...
        };
    }

    render() {
    	return (
    		<div>
        	    Practice App
        	</div>
    	);
    }
}

export default Header;

하지만 Typescript에서 위와 같은 코드를 사용할 경우, Type을 찾을 수 없다는 오류 메시지를 만나게 됩니다. 따라서 우리는 Props와 State를 어떻게 사용할 것인지 그 양식을 정해줘야 합니다. 

Typescript에서는 이를 정의할 수 있는 2가지 방법이 있습니다.

  • Type을 사용하는 방법
  • Interface를 사용하는 방법

Props, State 둘 다 사용하는 방법은 같습니다. Interface는 OOP 언어를 자주 사용하는 분들이라면 눈치채셨을 것입니다. 보통 Java에서는 인터페이스를 클래스의 메소드를 미리 정의할 때 사용했었죠. Typescript에서는 메소드 뿐만 아니라, 데이터의 타입도 미리 정의할 수 있습니다.

반대로 Type 문법은 C, C++에서 typedef struct와 비슷합니다. 구조체를 정의할 때 자주 사용하는 typedef는 실제로 타입을 재정의하는 방법이고, struct는 데이터 타입이 서로 다른 변수를 사용할 때 쓰는 방법이죠. Typescript에서는 데이터 타입이 서로 다른 변수를 저장해놓고 이 이름을 정의까지 하는 것까지 가능합니다.

 

Class-like

import React, { Component } from 'react';

type appProps = {};

type appState = {
    title: string;
}

class Header extends Component<appProps, appState> {
    constructor(props: appProps) {
    	super(props);
        
        this.state = {
            title: "Practice App"
        };
    }
    
    render() {
    	return (
            <div>
            	{this.state.title}
            </div>
        );
    }
};

export default Header;

 

type으로 정의할 때는 반드시 = 을 붙여주세요.

 

import React, { Component } from 'react';

interface appProps {}

interface appState {
    title: string
}

class Header extends Component<appProps, appState> {
    constructor(props: appProps) {
    	super(props);
        
        this.state = {
            title: "Practice App"
        };
    }
    
    render() {
    	return (
            <div>
            	{this.state.title}
            </div>
        );
    }
};

export default Header;

interface로 정의할 때는 Java와 동일하게 진행하 되, 각 변수 이름과 타입은 Json 정의하 듯만 진행하면 됩니다. 

Class를 사용하여 프로그래밍할 때는 생성자에 state 값을 초기화 하는 방법도 있지만 Type이나 Interface에 직접 그 값을 초기화 해줄 수 있는 방법도 있습니다. 생성자에서 값을 초기화 할 경우, Props의 데이터 타입을 정의해줘야 합니다.

 

import React, { Component } from 'react';

interface appProps {
    subTitle?: string;
}

interface appState {
    title: string;
}

class Header extends Component<appProps, appState> {
    constructor(props: appProps) {
    	super(props);
        
        this.state = {
            title: "Practice App"
        };
    }
    
    render() {
    	return (
            <div>
            	{this.state.title}
            </div>
        );
    }
};

export default Header;

단, Props의 데이터 타입을 정하여 컴포넌트의 Generic할 경우, 상위 컴포넌트에서 반드시 해당 Props의 값을 넣어야 합니다. 만약 아무런 값도 넣지 않을 경우, 오류가 발생하며, 이 오류는 마치 Java의 NullPointerException과 흡사한 모습으로 보여줍니다.

만약 데이터만 정의하고, 나중에 이 값을 넣으려 한다면, 각 변수에 '?'를 사용하여 이 값이 NULL일 수도 있음을 알려주세요.

 

Functional Programming

함수형 프로그래밍으로 사용할 때는 약간의 차이가 있습니다. React 16.x 버전부터 새로이 나온 React Hooks를 사용할 때는 interface나 type 문법으로 State를 정의해주지 않아도 됩니다. 

import React, { useState } from 'react';

interface appProps {
    title?: string;
    subtitle?: string;
}

const Header = ({ title, subtitle }: appProps) => {
    const [msg, setMsg] = useState('Welcome to My App');
    
    return (
        <div>
            {msg}
        </div>
    );
};

export default Header;

useState는 React 16.x에서 새로이 나온 함수이며 state 값을 정의하거나 바꿀 때 사용하는 함수입니다. 기존에는 setState라는 비동기 메소드를 사용하였지만 함수형 프로그래밍에서는 useState라는 함수를 사용하여 state 값을 변경할 수 있습니다.

comments powered by Disqus

Tistory Comments 0