React tutorial(tic tac toe)を動かす前に
ここでは、以下のチュートリアルを見ながら、実際にReactを動かしていきます。
まず一度、Reactの知識ゼロから、上の2つの記事のチュートリアルを作成しました。
分かったことは、
- とりあえず、その記事の通りにやれば動くものは出来た。
- ただし、何をやっているのかReactがどのような仕組みかよく分からない。
新しい言語なので当たり前なのですが、分からないということが理解できました。
そこで、Reactのドキュメントを見ながら、一つ一つの要素を分解して細かく見てきます。
それが終わった時点でもう一度、上2つのチュートリアルを振り返りたいと思います。
この記事では、componentとstateについて、説明していきます。
Componentについて
まず、基本的な仕組み、用語を整理したいと思います。
- elelment(要素)は、画面上で見たいものを記述する
- Reactの要素は不変です。なので、UIを更新する基本的な方法は、新しい要素を作成し、それをReactDOM.render()に渡すことです。
ここまでがelementの説明です。次によく出てくる単語コンポーネントについてです。
- componentsはそれぞれの要素によって構成されています
- コンポーネントを使用すると、UIを独立した再利用可能な部分に分割し、各部分について個別に考えることができます。
- 概念的には、コンポーネントはJavaScript関数のようなものです。 任意の入力(これがprops)を受け入れ、何がスクリーンに現れるのかを記述するReact要素を返します。
では、実際のコード例をみて、どのような処理がcomponent, elementに行われているのかを見ていきます。
function Welcome(props) {
return <h1>hello, {props.name}</h1>;
}//props = {name: 'sara'}
const element = <Welcome name='Sara' />;ReactDOM.render(
element,
document.getElementById('root')
);
- ReactDOM.render()で<Welcome name = “Sara” />要素を呼びます。
- Reactは、{name: ‘Sara’}をprops(引数)として、Welcomeコンポーネントを呼んでいます。
- Welcomeコンポーネントは結果として<h1> Hello、Sara </ h1>要素を返します。
- React DOMは、<h1> Hello、Sara </ h1>と一致するようにDOMを効率的に更新します。
またコンポーネントは、出力時には他のコンポーネントを参照できます。
<func />, または{func}のように呼ばれます。
Stateについて
まず基本的なReactのルールとして、すべてのReactコンポーネントは、その引数に関して純関数のように動作しなければなりません。
Stateは、Reactコンポーネントが、このルールに違反することなく、ユーザアクション、ネットワークレスポンス、およびその他の何らかの要求に応答して、時間の経過とともに出力を変更できるようにします。
例えば、以下の例を見ていきます。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
//props = {name: 'sara'}
const elm = <Welcome name='Sara' />;function Clock(props) {
return (
<div>
{elm}
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
}function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}setInterval(tick, 1000);
上の例でも機能するのですが、Clockはタイマーを設定し、毎秒UIを更新するという事実は、Clockの実装の詳細でなければなりません。
つまり理想的には、これ(setInterval)をClockコンポーネント内に書いて、コードのRefactoringをしたいと思います。
以下コードが、その結果です。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// props = {name: 'sara'}
const elm = <Welcome name='Sara' />;class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}componentWillUnmount() {
clearInterval(this.timerID);
}tick() {
this.setState({
date: new Date()
});
}render() {
return (
<div>
{elm}
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}ReactDOM.render(
<Clock />,
document.getElementById('root')
);
何が起こっているのか、メソッドが呼び出される順序を見てみましょう。
- <Clock />がReactDOM.render()に渡されると、ReactはClockコンポーネントのコンストラクターを呼び出します。 Clockは現在の時刻を表示する必要があるため、this.stateを現在の時刻を含むオブジェクトで初期化します。後でthis.stateを更新します。
- Reactは、Clockコンポーネントのrender()メソッドを呼び出します。 そこでReactがスクリーンに何を表示すべきかを知ります。
Reactは、Clockのレンダリング出力と一致するようにDOMを更新します。 - Clock出力がDOMに挿入されると、ReactはcomponentDidMount()ライフサイクルフックを呼び出します。その中で、Clockコンポーネントはブラウザに、tick()を1秒に1回呼び出すタイマーを設定するように要求します。
- 要求通り、毎秒ブラウザはtickメソッドを呼び出します。その内部で、Clockコンポーネントは、現在の時刻を含むオブジェクト(new Date())を使ってsetState()することで、UIの更新をスケジュールします。
- setState()呼び出しのおかげで、Reactは状態が変更されたことを知り、render()メソッドを再度呼び出して画面上に何が表示するかを知ることができます。今回は、renderメソッドのthis.state.dateが異なるため、レンダリング出力には更新された時刻が含まれます。 Reactはそれに応じてDOMを更新します。
- ClockコンポーネントがDOMから削除された場合、ReactはcomponentWillUnmount()ライフサイクルフックを呼び出し、タイマーを停止します。
また、クラスコンポーネントは常に、constructorをpropsとセットで呼び出す必要があります。
因みにコンポーネント内に追加された、componentDidMount()、componentWillUnmount()などはライフサイクルメソッドと言われるみたいです。
// Wrong this.state.comment = 'Hello';// Correct this.setState({comment: 'Hello'});// Wrong this.setState({ counter: this.state.counter + this.props.increment, });// Correct
this.setState((prevState, props) => ({ counter: prevState.counter + props.increment }));
また、setState()を使う際は以下の点に注意が必要です。
- this.stateを割り当てることができる唯一の場所は、コンストラクター内だけです。他の場所では行なえません。
- stateに変化を加える場合、直接this.state.propをやるのではなく、setState()を使います。
- stateの更新は非同期的に行われます。
感想
今回は、componentとstateについて見ていきました。
特にコンポーネントの処理の動きを見ることが、Reactの理解に大きくは、つながっていることが分かりました。
次の記事に、React内で使われているJS構文JSX、またコンポーネントについてもう少し詳しく見ていきます。
