かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Visual Studio上のTypeScript JSXを使ってReact.js「Hello ReactComponnent」

今まではタグを組み立ててただけですが、今回はReactComponentというものを作ります。

propsとstateというものをReactComponentを持ってるみたいですが、propsはイミュータブルでstateに変更する予定のある値を突っ込むみたいなイメージっぽいです。ReactComponentを作るには、React.Component<TProps, TState>を継承したクラスを作ります。TPropsにpropsのインターフェース、TStateにstateのインターフェースを指定します。

とりあえず、今回はボタンをクリックすることでh1タグの要素を消したり出したりする簡単なものを作ってみたいと思います。textプロパティでh1タグに表示する内容を指定できるようにしてみたいと思います。

まず、TPropsに指定するプロパティのインターフェースを定義します。textという文字列のプロパティを持っただけのインターフェースです。

interface ToggleComponentProperties {
    text: string;
}

次に、TStateに指定するインターフェースを定義します。これはh1を表示するか非表示にするかというvisibleというboolean型のプロパティを持たせることにします。

interface ToggleComponentState {
    visible: boolean;
}

次に、React.Componentを継承したクラスを定義します。

class ToggleComponent extends React.Component<ToggleComponentProperties, ToggleComponentState> {
}

このクラスにはコンストラクタでpropsを受け取るのとstateを初期化する処理を書く必要があります。

constructor(props: ToggleComponentProperties) {
    super(props);
    this.state = { visible: true } as ToggleComponentState;
}

visibleを切り替えるボタンクリックのイベントハンドラを用意しておきます。

handleClick(): boolean {
    this.setState({ visible: !this.state.visible } as ToggleComponentState);
    return false;
}

そして、renderでタグの組み立てを行います。visibleがtrueの時はsectionにh1とbuttonを出して、falseのときにはsectionにbuttonだけを置くようにしてます。

render() {
    var header = <h1 className='header'>{this.props.text}</h1>;
    var button = <button onClick={this.handleClick.bind(this) }>Toggle!</button>;

    if (this.state.visible) {
        return <section>
                {header}
                {button}
            </section>;
    }

    return <section>{button}</section>;
}

buttonのonClickにhandleClickを渡すときにbindをしてthisを指定してやらないと、ちょっとはまります。

最後に、ReactDOMのrenderメソッドで、作成してReactComponentを表示します。

ReactDOM.render(
    <ToggleComponent text='Hello React!!' />,
    document.getElementById('content'));

実行してボタンを押すとHello React!!の文字が表示されたり消えたりします。

コード全体

app.tsx

/// <reference path="typings/tsd.d.ts" />

interface ToggleComponentProperties {
    text: string;
}

interface ToggleComponentState {
    visible: boolean;
}

class ToggleComponent extends React.Component<ToggleComponentProperties, ToggleComponentState> {
    constructor(props: ToggleComponentProperties) {
        super(props);
        this.state = { visible: true } as ToggleComponentState;
    }

    handleClick(): boolean {
        this.setState({ visible: !this.state.visible } as ToggleComponentState);
        return false;
    }

    render() {
        var header = <h1 className='header'>{this.props.text}</h1>;
        var button = <button onClick={this.handleClick.bind(this) }>Toggle!</button>;

        if (this.state.visible) {
            return <section>
                    {header}
                    {button}
                </section>;
        }

        return <section>{button}</section>;
    }
}

ReactDOM.render(
    <ToggleComponent text='Hello React!!' />,
    document.getElementById('content'));

index.html

<!DOCTYPE html>

<html lang="ja">
<head>
    <meta charset="utf-8" />
    <title>TypeScript HTML App</title>
</head>
<body>
    <div id="content"></div>
    <script src="bower_components/react/react.min.js"></script>
    <script src="bower_components/react/react-dom.min.js"></script>
    <script src="bower_components/react/react-with-addons.min.js"></script>
    <script src="app.js"></script>
</body>
</html>