名もなき未知

エンジニアリングとか、日常とかそういうのをまとめる場所。

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 に関しての注意点は実際に書いてみると忘れそうなので、また見直してみようと思います。