React勉強メモ (環境構築からStateまで)

はじめに

JavaScriptのライブラリであるReactの勉強メモです.
今回は環境構築から,Stateまでのメモです.

環境構築

前提

Node.jsとnpmのバージョンは以下の通りです.

$ node -v
v6.11.3

$ npm -v
3.10.10

create-react-appのインストール

Reactアプリケーションの初期設定をしてくれるcreate-react-appをnpm経由でインストールします.

$ npm install -g create-react-app

Reactアプリケーションの初期設定

$ create-react-app appName

開発用サーバの起動

$ npm start

React

公式ドキュメントである https://reactjs.org/docs を参考に進めていきます.

ここから先,
HTMLは,appName/public/index.html
JavaScriptは,appName/src/index.jsを操作しているものとします.

index.html の中身は以下の通りです.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF=8" />
        <title>React</title>
    </head>
    <body>
        <div id="root">
        </div>
    </body>
</html>

index.js では,先頭で以下の2つのモジュールをインポートしているものとします.

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render

ReactDOM.renderを用いることで,HTML内の指定したエレメントに対してビューを挿入することができます.

ReactDOM.render(
    <h1>Hello, React!</h1>,
    document.getElementById("root")
)

JSX

Reactでは,エレメントを表現する際にJSXを用います.

JSXの外観はHTMLとほぼ同じですが,あくまでJavaScript上で評価される式として動作します.
そのためJSXは,変数に格納したり,関数の引数にしたり,返り値にしたりできます.

let element = (
    <div>
        <p>Hello, JSX!</p>
    </div>
);

ReactDOM.render(
    element,
    document.getElementById("root")
)

JSXの組み込み

JSXでは,中括弧{...}を用いることで,エレメントの中身や属性にJavaScriptの値を組み込むことができます.
以下は,pエレメントにformatName関数によって整形された名前をJSXの組み込み記法を用いて組み込むデモです.

let formatName = name => name.first + " " + name.last;
let myName = {
    first: "hogehoge",
    last: "fugafuga"
};
let element = (
    <p>
        Hello, {formatName(myName)}
    </p>
);

ReactDOM.render(
    element,
    document.getElementById("root")
);

Component

Reactでは,あるまとまったUIを再利用可能な形で扱うことが可能です.
このまとまったUI部品をコンポーネントと呼びます.

コンポーネントは,React.Componentクラスを継承したクラスを定義することで作成することができます.コンポーネントを定義することで,それをあたかもHTMLエレメントのように扱うことができます.

// UserInfoコンポーネントをレンダリングする例
ReactDOM.render(
    <UserInfo />,
    document.getElementById("root")
);

コンポーネント内では,そのコンポーネントが管理するUIに組み込む情報をpropsというプロパティで管理します.propsへの値の受け渡しは,以下のようにして行えます.

// UserInfoコンポーネントのpropsに,nameとageという情報を渡す例
let name = "Szarny";
let age = 20;

ReactDOM.render(
    <UserInfo name={name} age={age} />,
    document.getElementById("root")
);

コンポーネントrender関数によって,自身が管理するUIビューを返却します.
この時,propsにて管理している情報を組み込みます.

// render関数にてpropsのnameとageを組み込む例
render() {
    return (
        <p>Hello, {this.props.name} ({this.props.age} years old)</p>
    );
}

コンポーネントは,異なるコンポーネントを内包することができます.

例えば,とある投稿情報(postData)に関するUIコンポーネントについて考えます.
投稿情報は,以下の内容によって構成されるとします.

  • アバター画像とユーザ名から成る投稿者情報(UserInfo)
  • テキストと投稿日時から成ると投稿内容情報(ContentInfo)

これを実現するコンポーネントの組み合わせ例を以下に示します.

// 投稿者情報コンポーネント
const UserInfo = class extends React.Component {
    render() {
        return (
            <div id="user-info">
                <img
                    src={this.props.userInfo.imgUrl}
                    alt={this.props.userInfo.userName}
                />
                <h2>{this.props.userInfo.userName}</h2>
            </div>
        );
    }
}

// 投稿内容情報コンポーネント
const ContentInfo = class extends React.Component {
    render() {
        return (
            <div id="content-info">
                <p>{this.props.contentInfo.text}</p>
                <p>{this.props.contentInfo.date}</p>
            </div>
        )
    }
}

// 投稿情報コンポーネント
const PostData = class extends React.Component {
    render() {
        return (
            <div id="post-data">
                <UserInfo userInfo={this.props.postData.userInfo} />
                <ContentInfo contentInfo={this.props.postData.contentInfo} />
            </div>
        )
    }
}

// propsに渡すデータ
const postData = {
    userInfo: {
        imgUrl: "example.com/hoge.jpg",
        userName: "Szarny"
    },
    contentInfo: {
        text: "hello from component",
        date: new Date().toLocaleTimeString()
    }
}

// レンダリング
ReactDOM.render(
    <PostData postData={postData} />,
    document.getElementById("root")
)

State

Reactコンポーネントは,自身の状態を保持するためにpropsとは異なるstateというプロパティを持ちます.
stateのもっとも単純な利用方法は以下の通りです.

class ... {
    constructor(props) {
        super(props);
        this.state = { // 監視したい値 }
    }

    componentDidMount() {
        // DOMがマウントされた際に実行する処理
    }

    componentWillUnmount() {
        // DOMがアンマウントされた際に実行される処理
    }

    somefunction(){
        this.setState({
            // 変更したい値
        });
    }

    render(){
        ....
    }
}

以下は,stateを利用したカウンターの実装例です.

const Counter = class extends React.Component {
    constructor(props) {
        super(props);
        this.state = { value: 0 };
    }

    componentDidMount() {
        this.timerId = setInterval(
            () => this.increment(),
            1000
        );
    }

    componentWillUnmount() {
        clearInterval(this.timerId);
    }

    increment() {
        // prevState(1つ前のstate)のvalueと
        // propsで与えられたincrementを加算して
        // this.state.valueにセット
        this.setState((prevState, props) => ({
            value: prevState.value + props.increment
        }))
    }

    render() {
        return (
            <p>Counter: {this.state.value}</p>
        );
    }
}

let increment = 1;

ReactDOM.render(
    <Counter increment={increment} />,
    document.getElementById("root")
);

おわりに

またの機会に,ドキュメントの後半をやっていきます☺