名もなき未知

エンジニアリングとか、日常とかそういうのをまとめる場所。アクセス解析のためGAを利用、Googleに情報を送信しています。商品紹介のためAmazonアフィリエイトを利用、Amazonに情報を送信しています。記事に関しては私が書いていない引用文を除いて自由にご利用ください。

Reactのguide to main conceptsを読み始める人~その3~

継続力ですよ。

概要

この辺を読みます。今回はマジで新しく読む。てか長かったので 1 章分だけにする。

State and Lifecycle

ステートとライフサイクルについて、なのですごく大事そうな予感がする。詳細はここ React.Component – React

とりあえず前回作った 1 秒ごとに更新される時計をもう少しやっていくらしい。

function Clock(props) {
  return (
    <div>
      <h1>おはようございました~</h1>
      <h2>今は{props.date.toLocaleTimeString()}です~</h2>
    </div>
  );
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('kiryu')
  );
}

setInterval(tick, 1000);

まあどう考えてもレンダリングは1回にしたいし、そのためには Clock をレンダリング対象にする必要がある。それをステートを使って表現していく。

Function から Class に変更する。

class Clock extends React.Component {
    render() {
        return (
            <div>
                <h1>おはようございました~</h1>
                <h2>今は{this.props.date.toLocaleTimeString()}です~</h2>
            </div>
        );
    }
}

続く文章はあんまり理解できてはないんだけど、Class として定義することによって、Clock がインスタンスとして扱えるようになる。 これによってローカルでステートを持ったり、ライフサイクルメソッドを使ったりできる(この文は重要っぽい)

で、それに従ってコンストラクタの定義や state を登録していったらこういう形になった(すごく直感的でよい)

class Clock extends React.Component {
    constructor(props) {
        super(props);
        this.state = {date: new Date()};
    }

    render() {
        return (
            <div>
                <h1>おはようございました~</h1>
                <h2>今は{this.state.date.toLocaleTimeString()}です~</h2>
            </div>
        );
    }
}

function tick() {
    ReactDOM.render(
        <Clock />,
        document.getElementById('kiryu')
    );
}

親クラスのコンストラクタを呼びつつ、state に日付情報を持つような形。

この状態でさらに、ライフサイクルメソッドである componentDidMount, componentWillUnmount を刺してみる。

this.props は React 自身が用意し、this.state は特別な意味があるので、このように使える。自分で使いたいものは自分で定義してくださいと。

なのでここでは timer を登録/削除を行ってる。そして timer を通して state を変更することで、時間の更新を実現している。

class Clock extends React.Component {
    constructor(props) {
        super(props);
        this.state = { date: new Date() };
    }

    // ClockがDOMに挿入されるときに呼ばれる
    componentDidMount() {
        // 1234 とか不真面目にするとたまに1秒飛んで表示される
        this.timerID = setInterval(
            () => this.tick(),
            1000
        );
    }

    // ClockがDOMから削除されるときに呼ばれる
    componentWillUnmount() {
        clearInterval(this.timerID);
    }

    tick() {
        this.setState({
            date: new Date()
        });
    }

    render() {
        return (
            <div>
                <h1>おはようございました~</h1>
                <h2>今は{this.state.date.toLocaleTimeString()}です~</h2>
            </div>
        );
    }
}

ReactDOM.render(
    <Clock />,
    document.getElementById('kiryu')
);

State についての注意点は

  • setState() を使って更新し、直接更新しない
  • this.propsthis.state は非同期に更新なので、直参照すべきではない。使うのであれば、function でラップして受け付ける。
    • カウンターとかで関連するかも
  • setState() では結果がマージされるので、別々の箇所で update していたとしても、入れたものは取り出すことができる
    • 同じ名前の要素が色々な場所で更新される場合は要注意かも
  • データは下のものに伝わる(おそらく子のほうに流れるって意味だと思ってる)
    • state はローカル定義なので、カプセル化されている。子のコンポーネントには当然渡すことができる。
    • ただ子のコンポーネント的には、それがどのようなデータなのかはわからない(props, state, または手打ちなのかの判断ができない)

おまけ

知らなかった単語を並べる。

  • crucial: 決定的な、非常に重大な

まとめ

いきなりクラスっぽくなって、再利用可能な UI を作るためのノウハウを叩き込まれたような気がします。

またデータフローに関しても割とカプセル化されていつつも、state っていう特殊なやつがよし何やってくれそうなので、利便性は高そうです。

(でも何でもかんでも state に突っ込まれるみたいなパターンもあって、重複するようなキーを更新してバグるとかあると、大変なんだろうなぁ…)

あとは直接編集しないとかも大事ですね。state に関しての注意点は実際に書いてみると忘れそうなので、また見直してみようと思います。