前回のReact~基礎編~APP開発では、Reactのより実践的なアプリケーション開発について学習しました。今回は、ReactのStateについて、学びましょう。
<目次>
State概要

Stateを学んで、面白いアプリケーションを作れるようになりましょう!
より高度なアプリケーションを開発したい場合は、ステートフルなユーザーインターフェースの導入を検討してみてはいかがでしょうか?
「ステートフル」とは、状態を持たないという意味で、例えば次のような実装です。
・ログイン済みユーザーと未ログインユーザーの画面の見え方の違い
・「編集ボタン」をクリックした時、モーダル画面が表示される
・「read more」をクリックした時、WEBページが表示(あるいは非表示)される
つまりは、ユーザーの状態や操作によって、画面の状態が固定化されず、常に流動的に変化するアプリケーションを指しています。
Stateは、画面上で発生するイベントに対して絶えず変化するように設計されています。
そしてReactには、そのイベントをトラックする仕組みが、2つあります。
・UI logic – インターフェースの変更をトラック
・Business logic – データの変化をトラック
React State
React State は、コンポーネント上のインスタンス属性です。私たちがトラックしたいkeys/valuesの状態でオブジェクトとして存在ます。
1 2 3 4 5 6 7 8 |
// コンポーネントの状態を確認する console.log(this.state); // 出力結果 { gameName: "Soccure", score: 5 } |
Initial State
React Stateは、コンポーネントの作成直後に初期化するべきです。サンプルを載せておきます。
1 2 3 4 5 6 7 8 |
class howManyBook extends Component { constructor(props) { super(props); this.state = { numBooks: 0 // 初期化(keys/values) }; } } |
React Constructor Function
コンポーネントがステートレス状態の場合、constructor functionを省略できます。一方、ステートフルな状態(State)でコンポーネントを構築したい場合は、React Constructorが必要になってきます。
1 2 3 4 5 6 |
constructor(props) { super(props); this.state = { /* トラックしたい値を書き込む */ }; } |
3つのポイントがあります。
- constructorは、porpsを引数に受け取る
- React Componentとして登録する為、super(props)の呼び出しは必須
- インスタンスメソッド内では、this.stateにてオブジェクトを参照できる
State Sample
Stateのまとめとして、サンプルを載せておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Examination extends Component { constructor(props) { super(props); // コンポーネントとして登録 this.sate = { // トラッキングしたい値を入力 student: 'Monkey', score: 0, }; } render() { return ( <div> <h1>Programming Test</h1> <p>Current Student: {this.state.student}</p> <p>Score: {this.state.score}</p> </div> ); } } |
Changing State
コンポーネントのStateの状態を変えたい場合は、「setState」関数を使用できます。この関数は、Reactの組み込み関数です。
1 |
this.setState({name: "Harry", score: 0}) |
特徴は次の通りです。
・ コンストラクターを除く全てのインスタンスメソッドの中で呼び出せる
・ State変更状態のオブジェクトを受け取れる
・ State オブジェクトにパッチを適用する(未指定Keyは変更されない)
・ 非同期
- コンポーネントの状態は、最終的にアップデートされる
- パフォーマンスなどの理由により、State が変更された際にReactが制御する
・ Stateが変わった時、コンポーネントが再度、レンダリングされる
やってみよう
学んだことをアウトプットしましょう。
まずは、Reactプロジェクトを作成します。
1 2 3 |
create-react-app games cd games npm start |
srcディレクトリに以下のファイルを作成してください。
1 |
touch src/Games.js |
続いて、Games.jsに以下のコードを書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
src/Games.js import React, { Component } from 'react' class Game extends Component { constructor(props) { super(props); this.state = { socre: 0, gameOver: false } } render() { return ( <div> <h1>Your Score Is: {this.state.socre}</h1> </div> ) } } export default Game; |
このGameコンポーネントをApp.jsに組み入れましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
src/App.js import React, { Component } from 'react'; import Game from './Games'; import './App.css'; class App extends Component { render() { return <div className="App"> <Game /> </div>; } } export default App; |
ブラウザから結果を確認します。

コンポーネントの実装はできていますね。
Game.jsを改造して、数値が動的に変更されるようにしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Game.js import React, { Component } from 'react' class Game extends Component { constructor(props) { super(props); this.state = { num: 0, color: 'purple'}; this.makeTime(); } makeTime() { setInterval(() => { let rand = Math.floor(Math.random() * this.props.maxNum); this.setState({num: rand}); }, 1000); } render() { return <h1>{this.state.num}</h1> } } export default Game; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
App.js import React, { Component } from 'react'; import Game from './Games'; import './App.css'; class App extends Component { render() { return <div className="App"> <Game maxNum = {7} /> </div>; } } export default App; |


秒間隔で画像の通り、数値が変更されていくようにしました!
React Event

Stateは、ユーザー操作によって発生するブラウザのイベントでも変更できます!
Reactのイベント処理を学びましょう。
先ほどのサンプルでは、javaScriptのよって、動的にStateの状態を変更しました。それ以外にも、ユーザー操作(ドラッグ、フォームの送信、key入力など)に伴うブラウザのイベントでもStateの状態は変更できます。
ブラウザのイベントを担う属性は、JSXが保有しています。
例えば、クリックイベントを例に挙げます。クリックイベントを表す「onClick(キャメルケースで記載)」では、次の通りにイベントを発生させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Button.js import React, { Component } from 'react'; class Button extends Component { render() { return( <button onClick={function() { alert('Hello World'); }} > Click Me! </button> ); } } export default Button; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
App.js import React, { Component } from 'react'; import Button from './Button'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <Button /> </div>); } } export default App; |


イベントをバインドさせるには?

イベントを扱う時に注意事項があります!
先ほどの例を少し発展させます。
Web画面に設置したボタンをクリックした時に、画面上の文字が動的に変更されるプログラムを作ってみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
BrokenClick.js import React, { Component } from 'react'; class BrokenClick extends Component { constructor(props){ super(props); this.state = { clicked: false}; } // Change react state when user clicked button handleClick(e) { this.setState({ clicked: true }) } render() { return ( <div> <h1>{this.state.clicked ? 'Clicked!!!' : 'Not Clicked'}</h1> <button onClick={this.handleClick}>Click Me!</button> </div> ) } } export default BrokenClick; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
App.js import React, { Component } from 'react'; import BrokenClick from './BrokenClick'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <BrokenClick /> </div>); } } export default App; |
画面を確認しましょう。

このとき、「Click Me!」を押下するとエラーになります。

何が起こったのでしょうか?
エラーが発生した箇所は、Broken.jsに定義した「this.setState」です。
thisキーワードは、「自分自身」を表す特別な変数です。プログラム内で自由に呼び出すことが可能あり、呼び出した場所や方法によってその中身が変化します。
先ほどの例では、handleClickは、Reactコンポーネント内に設定したbuttonタグに設置しました。
つまり、呼び出し元は、Reactコンポーネントになります。
しかし、Reactコンポーネントは、constructor内の状態を保持しているわけではないので、handleClick関数を経由して、this.setStateを変更させることはできないのです。
変更可能にするには、handleClickをconstructor内にバインドする必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import React, { Component } from 'react'; class BrokenClick extends Component { constructor(props){ super(props); this.state = { clicked: false}; this.handleClick = this.handleClick.bind(this) // new } // Change react state when user clicked button handleClick(e) { this.setState({ clicked: true }) } render() { return ( <div> <h1>{this.state.clicked ? 'Clicked!!!' : 'Not Clicked'}</h1> <button onClick={this.handleClick}>Click Me!</button> </div> ) } } export default BrokenClick; |
これで、ボタンをクリックしたら画面の文字列が変わるようになりました。

ただし、現状だと文字列が変化するのは一度きりになります。
総まとめ
Stateの総まとめとして、次のプログラムを作成してみましょう。




簡単なプログラムですが、今回の学習の要点が入っています。
<仕様>
・初期表示の数値は、1
・ボタンを押下することで、数値が変更される
・数値の変更範囲は、1~10かつ、ランダムに表示
・数値が7になったら「YOU WIN!」を表示し、ボタンを非表示にする
・Stateを使用すること
プログラミングの学習は、アウトプットが大切です。頑張りましょう。
サンプルを載せておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Clicker.js import React, { Component } from 'react'; class Clicker extends Component { constructor(props) { super(props); this.state = { num: 1}; this.getRandom = this.getRandom.bind(this); } getRandom() { // pick random number 1-10 let rand = Math.floor(Math.random() * 10) + 1; // update state with new rand this.setState({ num: rand }); } render() { return ( <div> <h1>Number is: {this.state.num}</h1> {this.state.num === 7 ? <h2>You WIN!</h2> : <button onClick={this.getRandom}>Random Number</button>} </div> ); } } export default Clicker |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
App.js import React, { Component } from 'react'; import Clicker from './Clicker'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <Clicker /> </div>); } } export default App; |
StateとPropsの要約
StateとPropsの違いは、次の通りです。
TERM | MUTABLE | PURPOSE |
---|---|---|
state | yes | 可変のコンポーネントデータを格納 |
props | no | 不変のコンポーネントデータを格納 |
状態変化を伴う挙動(ステートフル)を取らせたい時はStateを使い、挙動を固定(ステートレス)にしたい場合は、Propsを使うといったイメージでしょうか。
次回
次回は、Stateのより発展した使い方を学んでいきましょう。
コメントを残す
コメントを投稿するにはログインしてください。