━目次━
Reactハンズオンその3です。
1から順番にやるのをオススメします。
React初心者のためのハンズオン その1[勉強方法とReactの基本]
React初心者のためのハンズオン その2[Propsとコンポーネント化]
React初心者のためのハンズオン その3[Stateでの状態管理]
React初心者のためのハンズオン その4[API実行と一覧表示]
さて前回までで、JSXの書き方やコンポーネント化、Propsについて学びました。
今回はReactでアプリケーションを作成する上で最も重要なStateを紹介します。
これまで作ってきたのは静的な(動きのない)画面だったので、画面の状態を管理するためのStateは不要でした。
しかし実際のシステムでは1つの画面は様々な状態をもっており、逐一変更されています。
検索結果の一覧情報
ラジオボタンが押されているかどうか
エラーがあるか否か
これらの「状態」をReactでは全てStateとして管理していきます。
サクッっと学んでReactをマスターしましょう!
Reactの世界へようこそ!Bonjour React!!
Stateとはなんぞや
Propsが「コンポーネントに渡す引数」だとしたら、Stateは
「コンポ―ネントが持つ状態」
です。
Reactのコンポーネントは常にStateを見張っており、Stateが変更されたら勝手に再レンダリングされるようになっています。
しかも、画面全てが再レンダリングされるのではなく、State更新前とState更新後で影響がある差分のみ再レンダリングされるという優れものです。
仮想DOMという技術で実現しています。
上記の理由でReactなどのSPAは、従来の画面よりも画面の描画スピードが早いんですね。
なのでコンポーネントを設計する際に「変更がある部分はStateに持たせる」という判断が必要です。まぁ慣れればちょちょいのチョイです。
ハンズオンなのでどんどん書いて慣れていきましょう!
クラスコンポーネントを定義してみる
ここまで扱ってきたコンポーネントは全て、JavaScriptの関数がコンポーネントになった「関数コンポーネント」でした。
しかし関数コンポーネントはそのままではStateを扱うことができないため「クラスコンポーネント」を定義してやる必要があります。
(※今はReact Hooksと呼ばれる方法で関数コンポーネントでもStateを扱えるようになりましたが、以前はStateを持たせたいコンポーネントは全てクラスコンポーネントにする必要がありました。Hooksについては今後ハンズオンで取り扱いたいと思います。)
クラスコンポーネントは今後もなくならないと言われているので、まずは基本となるクラスコンポーネントを学習しましょう。
では、「components」フォルダ配下に「CountButton.js」という名前で新規ファイルを作成しましょう。
こうですね。
名前の通り、押せば数字が増えていくボタンのコンポーネントです。
いつものようにreactをimportします。もう慣れ慣れのなーれですね。
[CountButton.js]
1 2 |
import React from "react"; |
次にクラスコンポーネントの枠組みを書いていきましょう。
Reactの中のComponentというものをextendsして作成し、rederメソッドの中でreturnするのが基本的な形となります。
[CountButton.js]
1 2 3 4 5 6 7 8 |
import React from "react"; class CountButton extends React.Component { render() { return <></>; } } |
いつも通りexportも忘れずに
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 |
import React from "react"; class CountButton extends React.Component { render() { return <></>; } } export default CountButton; |
書き方に若干の違いはありますが、関数コンポーネントとそんなに大きな差はないかと思います!
ここから、stateを使用する場合もう少し枠組みを足していきます。
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = {}; } render() { return <></>; } } export default CountButton; |
これはもうおまじないだと思ってもらえば最初はOKです。
クラスコンポーネントを使いたかったらとりあえずここまで書いとけばOKなんじゃな!
そうだね。最初は別に見ずに書けるように覚えなくて良いからコピペで作っても大丈夫だよ。
では一旦コンポーネントが正常にレンダリングされるか確認していきましょう。
「0」という固定の文字のボタンを返却するように修正します。
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = {}; } render() { return <button>0</button>; } } export default CountButton; |
これまで同様、index.jsでimportして表示してみましょう。
[index.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import React from "react"; import ReactDOM from "react-dom"; import ColorfulMsg from "./components/ColorfulMsg"; import CountButton from "./components/CountButton"; const App = () => { return ( <> <h2>Reactハンズオン!</h2> <ColorfulMsg color="blue">Reactは難しくないよー</ColorfulMsg> <ColorfulMsg color="green">Vueも難しくないよー</ColorfulMsg> <ColorfulMsg color="red">Angularは、、、</ColorfulMsg> <CountButton /> </> ); }; ReactDOM.render(<App />, document.getElementById("root")); |
Stateを使って状態を変化させてみる
ではいよいよStateを使っていきましょう!
今回は先程のボタンに表示されていた「0」という部分の数字をStateとして管理し、ボタンが押される度に数字がカウントアップされるようにしたいと思います。
まず最初にStateとして使いたい変数をconstructorの中で初期化してあげる必要があります。
今回は「count」という変数名で「0」を初期値に設定してみます。
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { return <button>0</button>; } } export default CountButton; |
これでこのコンポーネントはcountという名前のStateを保持した状態になります。
ではこの値をボタンに表示していきましょう。
クラスコンポーネント内では「this.state.~」という形でStateにアクセスできます。
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { return <button>{this.state.count}</button>; } } export default CountButton; |
これで、表示が変わらず0のボタンがレンダリングされていればOKです!
さっきまでは「固定の0」を表示していたのに対し、今は「Stateの0」を表示している状態ですね。
では次にボタンのクリックイベントを作っていきましょう!
Reactのいやらしいところは素のHTMLやCSSと微妙に表記が違うということです。
例えば、クリックイベントで言うと「onclick=~」ではなく「onClick=~」となります。
「font-size:」とかも「fontSize:」と記述します。
まぁ全部キャメルケース(単語の繋ぎの文字が大文字)になるんだと覚えておけばOKです。慣れてしまえば林家ペーです。
クリックイベントはこんな感じ。「handleClick」という名前でクリックされたときに動く関数を作りましょう。関数名の前にもthisが必要なことに注意。
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { return <button onClick={this.handleClick}>{this.state.count}</button>; } } export default CountButton; |
では関数をかいていきます。いきなり中の処理を書いていくのではなく、まず関数が正常に呼ばれているかを確認するためにalertをかけてみましょう。
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { alert(); }; render() { return <button onClick={this.handleClick}>{this.state.count}</button>; } } export default CountButton; |
これで、ボタンを押した際に以下のようにアラートが表示されれば関数呼び出しはOKです。
さぁあとはこの関数内でStateをカウントアップして更新するだけですね!
ReactでStateを更新する場合、setState関数を用いる必要があります。
(※間違っても、「this.state = 1」みたいな更新をしてはいけません)
ではでは現在のStateに+1した値でStateを更新してみましょう!
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { this.setState({ count: this.state.count + 1 }); }; render() { return <button onClick={this.handleClick}>{this.state.count}</button>; } } export default CountButton; |
これでボタンをクリックしてみて、数字がカウントアップされていけば大成功です!
このようにthis.setStateに新しいStateオブジェクトを渡すことでStateの更新ができちゃいます。
最初に言いましたがこの時、CountButtonコンポーネントはStateが変更されるので再レンダリングされますが、上のタイトルやメッセージは再レンダリングされないのがミソです。Reactがええ感じにしてくれてます。
よっしゃぁ~!!できたー!!!
ちょっと待ったぁぁぁぁぁ~~~!!!!
????
実はさっきのコードには初学者がやりがちなミスが隠されています。
チョットデキル人に上のコードを見せたら、
「おいおいまったく困ったちゃんだなチミは」
とか言われちゃってちょっと気持ち悪いので修正していきましょう。
問題は何かと言うと、
this.setState({ count: this.state.count + 1 });
という部分です。
公式ドキュメントのこの部分にも書いてありますが、setStateでのState更新は即座に行われるわけではなく、場合によってはいくつかまとめて実行されたり遅れて実行されることもあります。
つまり上記の例で言うと、this.state.countが必ずしも今の最新のStateとは限らないということです。
(※このくらいシンプルなコンポーネントであれば問題はおきませんが…)
このように、「今のStateやPropsを基にStateを更新したい」という場合、setState関数には別の書き方を使用します。
それがsetStateに更新用の関数を渡す方法です。構文としては以下
setState((現在のState, 渡されているProps) => return (State更新用オブジェクト));
この方式で記述すれば、「現在のState」という部分のStateに+1すれば誤動作の心配がないので確実です。
先程のコードを修正してみましょう。
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { this.setState((state, props) => { return { count: state.count + 1 }; }); }; render() { return <button onClick={this.handleClick}>{this.state.count}</button>; } } export default CountButton; |
同じように動作すると思います。
今回はPropsは使わないので以下のように省略することもできます。
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { this.setState(state => { return { count: state.count + 1 }; }); }; render() { return <button onClick={this.handleClick}>{this.state.count}</button>; } } export default CountButton; |
更に1行で書くとこんな感じ。このあたりは単純にアローファンクションの話ですね。
[CountButton.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import React from "react"; class CountButton extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { this.setState(state => ({ count: state.count + 1 })); }; render() { return <button onClick={this.handleClick}>{this.state.count}</button>; } } export default CountButton; |
これで正常に動作すれば次こそ完成です!!ヤッタゼ!!
さいごに
JSXやコンポーネントにもだいぶ慣れてきたのではないでしょうか?
尚、このハンズオンのソースはGitHubで公開しています。
https://github.com/freelance-jak/react-handson_3_state
更にPropsとStateも使えるようになったので
「ワタクシ、リアクトカケマス」
と言っても大丈夫ですね!責任は持ちません!←
とまぁ冗談はさておき、大体の記事ではここまでの紹介で終わっており、
「じゃぁ実際にシステムを作るときみたいに、APIでデータ取ってきてそれを一覧で表示するとかどうするんだ??」
って手が止まると思います。
次はより実務に近い処理の流れである
「WebAPIでJSONデータを取得して、ループしながら一覧表示する」
ということをしてみたいと思います!
楽しみだぜ旦那ぁーーー!!
もし「分かり易い!」と感じたら是非のボタンからシェアしてReactの輪を拡げて頂けたらと思います!
それでは!また!!
人気の記事だけ集めたので是非覗いていってください^^
厳選!目的別にオススメ記事を紹介-あなたの欲しい情報がここに-