JSひろば開発6日目:Vueアプリのデプロイとデザイン

JSひろばアプリ作成まで~6日目

前回までの記事では、Djangoをデプロイし実際のドメインからアクセスできるところまで行いました。今日の作業ではバックエンドのDjangoアプリで作成したAPIのエンドポイントとVueのウェブアプリから実際にAPIのリクエストを送りバックエンドからデータをもらえるようにします。あとデザインをキレイにしましょう。 作業日 2022年12月16日 作業にかけた時間 8時間 合計作業時間 24時間 作業内容 Djangoに実際のデータを入力VueアプリにAxiosをインストールAPIコールのリスポンスをPiniaに保管実行ボタンの作成アニメーションの設定highlight.jsを設定 ではDjangoのアドミンページから実際のデータを入力してAPIのエンドポイントから取得できるようにします。 VueアプリにAxiosをインストール 次に、EventService.jsというAPI関連のコールをまとめた別ファイルを作成しました。 次にPiniaのファイルにAPIコールのファンクションを保管しておきPiniaが読み込まれたらデータをフェッチするようにします。どこでこのファンクションと発火させるかは後から変更するかもしれません。 ここで、APIのGETリクエストを送ると予定通りにCORSポリシーでDjangoからブロックされてしまいました。 詳しい対応方法はDjango REST API COR Headersの使い方の記事を参照してください。ではこの記事通りにいったんDjangoのアプリを更新してまた戻ってきましょう。 あと、Vue側のアプリケーションのindex.htmlのheadタグ内に下記のmetaを追加しました。 Vueアプリの検証 ではAPIの問題が解決したところでこのPrimeVueのターミナルで問題発生。。このUIだと改行ができないことが発覚しました。まあターミナルなのでそうでしょうが。なのでPrimeVueのTextAreaのコンポーネントと入れ替えました。 Vueアプリのデプロイ Vueアプリのデプロイはこの記事を参考にして行いました。これもLet’s EncryptとCertbotを使ってHTTPSからアクセスできるようにしました。 とりあえず、Vueアプリがデプロイできるようになりました。後はUIの調整と細かい設定をして完了です! アニメーションで使ったCSSはこちらの記事に書いています。Animistaというサイトです。 highlight.jsの追加 このままだと、テキストエディタのように色でハイライトされないので見づらいですね。highlight.jsをインストールしてみます。ここで入力したときと同時に1文字ずつでJavaScriptのキーワードかを判定してハイライトするようにしたかったのですが、うまくいきませんでした。テキストエリアをハイライトさせるのが難しそうでしたので諦めました。 しかし、他の方法でコマンドを実行したときにコードがハイライトされるようにできたので良しとします! もし、単純にダイナミックでないコードをハイライトしたいのであればVueのコンポーネントで使えるHighlight.jsのプラグインもあるので試してください。 とりあえず今日はここまで!

JSひろばアプリ開発5日目:Djangoのデプロイ

JSひろばアプリ作成まで~5日目

前回まではJSひろばのVueアプリとDjangoのAPIを大まかに作成しました。 今日はフロントエンドのVueのデプロイよりも先にDjangoのアプリをデプロイして実際のAPIを使ってVueからAPIコールができるようにします。実際にデプロイをしたあとに細かなセキュリティの設定やAPIのデータを入力していくようにします。 作業日 2022年12月14日 作業にかけた時間 5時間 合計作業時間 16時間 作業内容 ドメインの取得Ubuntuサーバーの設定サーバーのユーザー設定PostgreSQLのインストールリポジトリのクローンDjangoのデプロイNginxの設定SSLの取得 ドメインの購入 ドメインは〇〇.comとかウェブサイトのアクセスリンクになる部分ですね。今回は個人的なお勧めのNameCheap.comからドメインを購入します。APIの方もIPアドレスからAPIのエンドポイントを作成しようと思いましたがセキュリティの面からもドメインを使った方が良いとのことなのでDjangoとVueのアプリケーションのどちらにもドメインを割り当てます。 では、asameshi-api.cloudとjs-hiroba.comを購入します。合計で年間12ドルなので安いですね。SSL Certificate(HTTPS)は無料でサーバー側で設定できるのでここで購入する必要はありません。 サーバーにドメインを登録 今回もまた、個人的なお勧めのLinodeサーバーを使います。東京にサーバーを作りましたので先ほど購入したドメインをサーバーに登録しましょう。ではNameCheapのドメイン設定からカスタムDNSを設定します。 ところがLinode側で登録すると以前に設定していたサーバーと紐づけされてエラーになってしまいました。 これは私の方では何もできないので一旦、サポートにお願いをして待ちます。 その間にIPアドレスからデプロイしちゃいます。 サーバーの設定 まずはLinodeでサーバーを作ります。Linodeサーバーを月額500円で始めるという記事があるのでそちらを参考にしましょう。 サーバーを作成したらLinode側でドメインを登録します。 同じようにapiで使う方のドメインも登録しておきます。 サーバーにSSHで接続 詳しいSSHの使い方はこちらの記事で説明しています。サーバー構築で必ず役に立つので理解しておきましょう。 ではSSHクライアントを使ってサーバーに接続しましょう。SSHクライアントのMobaXtermを使います。 Djangoのデプロイ 詳しいDjangoのデプロイの仕方はこちらで説明しています。 同じような手順で設定していきましょう。 この後にデータベースを作成しましょう。 詳しくはDjangoのデプロイの仕方でカバーしているので確認しておきましょう。 次に仮想環境の設定です。 次にGunicornのテストをしました。 でNginxのコンフィグはこのようになりました。 ではNignxをテストして、サービスをリロードします。 ドメインをsettings.pyに登録していなかったのでエラーが出ました。しかしこれでDjangoのエラーのページが出たので正しくNginxとGunicornが動いていることが確認できますね。 これでサーバーを再起動してAPIのURLにアクセスすると問題が解決していることが確認できました。 しかしURLを見ても分かるようにまだHTTPのままなのでSSL Certificateを取得して安全なサイトにするようにします。 この作業はLet’s EncryptでSSL取得の記事を見て行いましょう。 ここで、安いプランのシェアサーバーだったせいか、SSLのセットアップに少し苦難し、2時間余計に時間がかかってしまいました。 特に、DNSを使ったSSL証明のチャレンジ、HTTPからHTTPSへのリダイレクトなど初めての作業だったのでとても良い経験になりました。

JSひろばアプリ開発4日目:Djangoプロジェクトの作成

JSひろばアプリ作成まで~4日目

前回まではVueのフレームワークを使い、フロントエンドのアプリを作成しました。まだモックのデータでしか操作できないので、実際にREST APIを作成したVue側で使えるようにしていきます。 今日は、PythonのウェブフレームワークのDjangoを使ってAPIを作っていきます。Flaskよりもアドミンページがあったりセキュリティの設定が最初から入っているなど開発の面でもスピードアップができる素晴らしいフレームワークです。 YouTubeでもDjangoとDjango REST APIを説明したプレイリストがあるので是非見てください。 作業日 2022年12月13日 作業にかけた時間 2時間 合計作業時間 11時間 作業内容 Djangoのプロジェクト作成virtualenvの設定requirements.txtに書き出しDRFのインストールDBのテーブルの構成モデル、URL、ビューの設定PostgreSQLに接続 Djangoのプロジェクト では早速Djangoのプロジェクトを作成します。Python3がインストールされていることを確認してください。 その前に仮想環境のvirtualenvが入っているか確認します。入っていない場合は下記のコマンドでインストールしましょう。 仮想環境の説明はこちらの動画を見てください。必ず役に立ちますよ。 では正しいファイルパスにいることを確認して下記のコマンドで仮想環境をアクティベートします。 これでプロンプトの最初に(env)と表示されればOKです。 Djangoのインストール ではDjangoとDjango REST Frameworkをインストールします。 他にも必要なパッケージがあればその都度インストールすると思いますが、今のところはなさそうです。 Djangoはバージョン4.1がリリースされているので最新のものを入れておきましょう。 必要であればgit initでリポを作成しましょう。詳しいGitとGitHubの使い方はこちらの動画を見てください。 では、下記のコマンドでDjangoのプロジェクトをスタートします。 次にmanage.pyのファイルを使ってDjangoのアプリを作成します。 次にを開発用の仮のデータベースをSQLiteで作成します。 その後にテストランしてみましょう。 これでセッションのテーブルができました。 では実際にブラウザにアクセスしてDjangoのデフォルトのページが表示されるか見てみます。 OKですね。では実際にコードに入ります。 アプリの登録 先ほど登録したcommandアプリをDjangoのプロジェクトに教えてあげます。 Settings.pyでcommandアプリとRESTフレームワークのアプリを登録しました。 次にプロジェクトフォルダのurls.pyにAPIのエンドポイントとなるURLを登録します。 このrouterファイルは後から作成します。まずはAPIの前にデータが登録できるところまで確認しましょう。 モデルの作成 ではデータベースの枠となるmodels.pyを作成していきます。 とりあえずはこんな感じで作成しました。 Views.pyの作成 Views.pyはモデルともとに何をするのか指示する場所になります。 ここではモデルをシリアル化してAPIを作成するように指示しています。 CommandSerializerのファイルがまだできていないのでそれを作成します。 CommandSerializer では同じファイルパスにserializers.pyを作成しましょう。 まずはこれだけ設定していきます。 admin.pyの登録 Djangoのアドミンパネルでテーブルが見れるようにモデルを登録します。 スーパーユーザーの登録 Djangoのスーパーユーザーを作成してアドミンパネルからテーブルが作成できるか見てみましょう。 再度テーブルのマイグレーションを行います。 … Read more

JSひろばアプリ開発3日目:Vueアプリの全体像

JSひろばアプリ作成まで~3日目

前回の記事では、Piniaを入れて大まかなレイアウトを作成しました。 今回はPiniaやemit()、テンプレートrefを使うのでVueの要素が盛りだくさんです。 今日で大まかなフロントエンドの部分を完了させます! 作業日 2022年12月12日 作業にかけた時間 3時間 合計作業時間 9時間 作業内容 ボタンのコンポーネントの作成モックのデータを作成グローバルで使うデータをPiniaに保管させるEmitを使いデータを親コンポーネントに送るライブラリコンポーネントのRefにアクセスする 3つのファインダーコンポーネント では、このJSひろばのアプリのメイン機能としてこの4つのファインダーがありましたがおすすめ検索機能はキーワード検索とほぼ同じなのでいったん取り除くことにしました。 これは、ユーザーがJavaScriptのサンプルコードを見つけるための機能になります。 ボタンのコンポーネント 各ボタンを押すとそれぞれのボタンに付属した内容が同じダイアログ(ポップアップ)のコンポーネント内で表示されるようにします。 まずは、各4種類の検索機能のコンポーネントをcomponents/finderフォルダに作成します。最初の中身はただのテキストでOKです。次にApp.vueに戻りPrimeVueにあるDialogコンポーネントをコピペします。 それから、各ボタンを押したときにそれぞれのコンポーネントの内容が表示されるようにロジックを作成すればOKです。 途中経過ですが、こんな感じになりました。 実際の画面はこんな感じです。 キーワード検索 まだ、データベースの細かい構成とデータの量を吟味していないので詳しくはすすめられません。ここで検討すべき課題はこちらになります。 このファインダー機能のコンポーネントは複雑になるので作成はいったん後回しにします。 Piniaの作成 Piniaを使ってグローバルにアクセスできるストレージを作成します。とりあえず、モックのJSONファイルを作成してテーブルとして表示できるところまでやってみます。 これを各テーブルで表示させるとこんな感じになりました。 履歴のデータを保管する 各コマンドを実行した後に、その履歴をオブジェクトの配列に保管します。常に最新の履歴が先に来るようにしたいため、pop()ではなく、unshift()を使っています。 コンソール関係のコードはこのような感じです。 これで入力したコマンドがオブジェクトとして配列に保管されました。テーブルにも問題なく表示されていることが分かります。 コードをコンソールにコピーする機能 では、検索機能で探したコマンドをコンソールにコピーするボタンのファンクションを作成していきます。ドキュメンテーションにはないですがこのターミナルがどうやって入力されたテキストをバインドしているか見てみましょう。 VueのGoogleエクステンションツールを使います。 VueのタブからTerminalのコンポーネントを開きます。すると、DataのところにcommandTextがあるのがわかります。ここがnullになっていますがターミナルにテキストが入力されると同時に更新されました。 では、このデータにコピーしたいコピーをバインドさせるようにします。 まず、ここのcommandTextにアクセスするには<Terminal ref=”terminal”/>のようにrefを使ってこのコンポーネント内にあるデータ、関数にアクセスすることができますね。(Compostion APIの場合は対象のコンポーネント側でexpose()されて公開されている必要がありますが。) あとは、テーブル側のボタンにemit()を設定して親コンポーネントにコマンドのデータを送ってあげます。 親コンポーネント側では、Emitを受け取ったときに発火するイベントを下記の様に設定してあげました。 細かいスタイルの変更 ここまでできたら、大体のレイアウトは決まったのでスタイルをキレイにしていきます。 特に、モバイルとデスクトップで共通のアプリを使えるようにしたいのでその設定も必要です。 とりあえずこんな感じになりました。ポップアップで表示されるダイアログは実際のデータが入ってからスタイリングをしたいと思います。 では、フロントエンドはこれくらいにして次回からにバックエンドにかかりましょう。 お疲れ様です。

JSひろばアプリ開発2日目:スタイルの設定

JSひろばアプリ作成まで~2日目

前回の記事ではアプリの概要とデザインを全体像として決めました。 今日は、もう少し具体的なフロントエンドのデザインを設計していきます。ファイル構成(どの段階でコンポーネントにするか)とPrimeVueのライブラリを見ながらサクサク進めていきたいです。 ちなみにバックエンドも同時に進めても良かったのですが、割と簡単な作業になりそうなので、モックのJSONファイルで先にフロントエンドでテストをしてからでも良いと判断しました。ですので先にVueのアプリケーションから固めていきます。 作業日 2022年12月10日 作業にかけた時間 3時間 合計作業時間 6時間 作業内容 Figmaのデザインを形にしていくファイル構成を考えるVueコンポーネントの作成Piniaのインストール PrimeFlexのインストール 前回入れていなかったので、今回使うCSSライブラリのPrimeVueで使うCSSユーティリティをインストールします。 これでクラスを使ってマージンの設定やFlexの設定ができるようになりました。 次にGoogleフォントを追加しました。CDNでfontをリンクさせました、必要に応じてフォントのファイルをダウンロードしてローカルから使うようにすることも考えています。 main.jsに下記のimport ‘@/assets/global.css’をインポートしました。 スタイルはできるだけPrimeVueのものを使い、カスタムしたい場合は.Vueファイルの下に<style></style>を作成してそこにCSSを書きました。 ざっくりと全体像を作成しました。 ユーザーエクスペリエンスの向上のために下記のことを先に達成したいです。 これを実現するにはいくつか方法がありますが、PrimeVueのコンポーネントでダイナミックダイアログというものがあったのでこれで対応していきます。 さらに上記でごちゃごちゃした検索機能とか、ボタンの枠を固定してボタンを押すとこのダイアログが表示されるようにします。なのでこれらはコンポーネントにまとめてあげましょう。 とりあえずポップアップが開くところまではOKですね。 Piniaのインストール 次にPiniaをインストールします。単純にreactive()でオブジェクトとしてデータまとめても良いのですが、propsでごちゃごちゃしていくと後からの修正が大変なので、グロバールでアクセスできるPiniaの方がよいと判断しました。 Piniaの使い方はこちらで説明しています。 ではPiniaのインストールが完了したらmain.jsに追加します。 その後にstore.jsというファイル名でアプリに使うデータをPiniaを使ってここに保管させます。 どのようなデータを保管するか具体的な構成は次回までに考えておきます。 とりあえずこんな感じでPiniaで作成したStoreデータをメインの画面に表示させることができました。 Piniaのファイルはこのように書きました。 App.VueのファイルにはこのようにPiniaをインポートしました。 では、次回にポップアップの中身と検索機能を作成していきたいと思います。 お疲れ様です。

JSひろばアプリ開発1日目:プロジェクトのセットアップ

JSひろばアプリ作成まで~1日目

私がプログラミングを独学で始めたのた2020年の3月、ニューヨークでコロナがちょうど発生した時でした。 それから片手間にPythonを1年くらい学び、その後にJavaScriptを後に学び始めました。 それからチケット管理アプリをデモで作りましたが、もっと実践で使えそうなアプリを作りたいと思い、今回のJSひろばアプリを作ることに決めました。 今回はプログラミングを始めたい人の為にすべての作業をゼロから行い、コードもすべてオープンソースで公開いたします。 作業の内容 作業日 2022年12月8日 作業にかけた時間 3時間 合計作業時間 3時間 作業内容 アイディアを絞るUIをFigmaでデザインする使用するテクノロジーを決める課題点をクリアする JSひろば JSひろばという名前でアプリを進めていきます。これは、ユーザーがJSエンジンのコンソールにウェブページからインプットできて、ファンクションやWindowオブジェクトの仕組みを実際に試しながら学ぶアプリです。 下記がアプリのイメージになります。 これは無料デザインツールのFigmaを使って作りました。詳しいFigmaの使い方はこの記事で紹介しています。 当初はユーザー登録をしてユーザーが好きなコードの投稿や、お気に入りのコードを登録する機能までつけてみようかと思いましたが、機能の実装までにかなり時間がかかりそうなのでとりあえずはなしで進めます。 今回のスタック JSひろばアプリは今まで使ってきたPtyhonのウェブフレームワークのDjangoとそれをREST APIにしてくれるライブラリを使います。 フロントエンドはReactを使おうかなと思ったけどVueの方が慣れているのでそちらを使います。 Djangoだとついてくるアドミンパネルからデータのエントリーができるのでこれもプラスですね。 では、今回のスタックDjango+PostgreSQL+Vueのイメージ図です。 eval()の脅威 今回、ユーザーがウェブページからeval()のメソッドを使ってコンソールと同じようにリスポンスを返すようにしたいのが一番の目的でした。しかしeval()はセキュリティ上使わない方がよいようですね。 有名なハッキング手法のうちの一つにEVAL インジェクション(eval injection)があることを知りました。 これは、JavaScriptのデーターフォーマットをであるJSON (JavaScript Object Notation)に不正なコードを挿入し想定外の動作を誘導する攻撃手法です。特にPHPをサーバーで使っている場合は危険のようですね。 今回は下記の点からeval()を使っても良いと判断しました。 Vueのプロジェクト作成 Vueのスタックはこんな感じです。 Vue + PrimeVue(UIライブラリ)+ Vite + Pinia 今回はさくさくに動くViteのビルドツールを使います。 とりあずJavaScriptでコンソールをウェブページに実装できるところまで進めます。 UIで使うCSSライブラリはPrimeVueにします。詳しいライブラリの説明はこちらで見てください。 TailwindCSSでもよかったのですが、PrimeVueに使えそうなターミナルのコンポーネントを発見しました! まさにこれをアプリのメインのターミナルとして使いたいですね。 ではPrimeVueもインストールしましょう。詳しいPrimeVueの設定の仕方はこちらを参照してください。 とりあえずここまでできました。 ではPrimeVueのコンポーネントを使ってキレイにしましょう。 細かいインプットの制限やコードの整理はまた次回に行います。 GitHubでコードを公開しているので見てください。 GitとGitHubの使い方もYouTubeで説明しているのでよかったらどうぞ。 完成したアプリはこちらからどうぞ。

React講座 React の流儀

React講座 開発までの流れ

基本講座の最後として、検索可能な商品データ表を React で作っていく様子をお見せします。 モックから始めよう すでに、JSON API が実装済みで、デザイナーからもデザインモックがもらえているとしましょう。モックは次のような見た目だったとします。 また、JSON API は次のようなデータを返してくるとしましょう。 Step 1: UI をコンポーネントの階層構造に落とし込む まず最初に行うのは、モックを形作っている各コンポーネント(構成要素)を四角で囲んで、それぞれに名前をつけていくことです。もしあなたがデザイナーと一緒に仕事をしている場合は、彼らがすでにこれに相当する作業を終えている可能性がありますので、話をしに行きましょう。彼らが Photoshop でレイヤ名にしていた名前が、最終的にはあなたの React コンポーネントの名前になりうるのです! しかし、どうやって単一のコンポーネントに括るべき範囲を見つけられるのでしょうか。ちょうど、新しい関数やオブジェクトをいつ作るのかを決めるときと、同じ手法が使えます。このような手法のひとつに、単一責任の原則 (single responsibility principle) があり、これはすなわち、ひとつのコンポーネントは理想的にはひとつのことだけをするべきだということです。将来、コンポーネントが肥大化してしまった場合には、小さなコンポーネントに分割するべきです。 JSON のデータモデルをユーザに向けて表示することはよくありますので、モデルを正しく構築されていれば、UI(つまりコンポーネントの構造)にもうまくマッピングされるということが分かるでしょう。これは、UI とデータモデルが同じ 情報の構造 を持つ傾向があるためです。UI を分割して、それぞれのコンポーネントがデータモデルの厳密に一部分だけを表現するよう、落とし込みましょう。 5 種類のコンポーネントがこのアプリの中にあることが見て取れます。それぞれの解説の中で、データを表すものについては太字にしました。図中の番号は以下の番号と対応しています。 ProductTable を見てみると、表のヘッダ(「Name」や「Price」のラベルを含む)が単独のコンポーネントになっていないことがわかります。これは好みの問題で、コンポーネントにするかしないかは両論あります。今回の例でいえば、ヘッダを ProductTable の一部にしたのは、データの集合を描画するという ProductTable の責務の一環として適切だったからです。しかしながら、将来ヘッダーが肥大化して複雑になった場合(例えばソート機能を追加した場合など)は、ProductTableHeader のようなコンポーネントにするのが適切になるでしょう。 さて、モック内にコンポーネントを特定できましたので、階層構造に並べてみましょう。モックで他のコンポーネントの中にあるコンポーネントを、階層構造でも子要素として配置すればいいのです。次のようになります。 Step 2: Reactで静的なバージョンを作成する さて、コンポーネントの階層構造が決まったので、アプリの実装に取り掛かりましょう。最初は、データモデルを受け取って UI の描画だけを行い、ユーザからの操作はできないというバージョンを作るのが、もっとも簡単でしょう。表示の実装とユーザ操作の実装を切り離しておくことは重要です。静的な(操作できない)バージョンを作る際には、タイプ量が多い代わりに考えることが少なく、ユーザ操作を実装するときには、考えることが多い代わりにタイプ量は少ないからです。なぜそうなのかは後で説明します。 データモデルを描画するだけの機能を持った静的なバージョンのアプリを作る際には、他のコンポーネントを再利用しつつそれらに props を通じてデータを渡す形で、自分のコンポーネントを組み上げていきましょう。props は親から子へとデータを渡すための手段です。もし、あなたが state に慣れ親しんでいる場合でも、今回の静的なバージョンを作る上では一切 state を使わないでください。state はユーザ操作や時間経過などで動的に変化するデータを扱うために確保されている機能です。今回のアプリは静的なバージョンなので、state は必要ありません。 コンポーネントはトップダウンで作っても、ボトムアップで作っても問題ありません。つまり、高い階層にあるコンポーネント(例えば FilterableProductTable)から作り始めても、低い階層にあるコンポーネント(ProductRow など)から作り始めても、どちらでもいいのです。シンプルなアプリでは通常トップダウンで作った方が楽ですが、大きなプロジェクトでは開発をしながらテストを書き、ボトムアップで進める方がより簡単です。 ここまでのステップを終えると、データモデルを描画する再利用可能なコンポーネントの一式が手に入ります。このアプリは静的なバージョンなので、コンポーネントは render() メソッドだけを持つことになります。階層構造の中で最上位のコンポーネント(FilterableProductTable)が、データモデルを props として受け取ることになるでしょう。元となるデータモデルを更新して再度 root.render() を呼び出すと、UI が更新されることになります。このやり方なら、複雑なことをしていないので、UI がどのように更新されて、どこを変更すればよいか、理解できることでしょう。React の単方向データフロー(あるいは単方向バインディング)により、すべてがモジュール化された高速な状態で保たれます。 ヒント:Props vs State React には 2 … Read more

React講座 コンポジション vs 継承

react-compostion

React は強力なコンポジションモデルを備えており、コンポーネント間のコードの再利用には継承する方法よりもコンポジションをお勧めしています。 この章では、React を始めて間もない開発者が継承に手を出した時に陥りがちないくつかの問題と、コンポジションによりその問題がどのように解決できるのかについて考えてみます。 子要素の出力 (Containment) コンポーネントの中には事前には子要素を知らないものもあります。これは Sidebar や Dialog のような汎用的な “入れ物” をあらわすコンポーネントではよく使われています。 このようなコンポーネントでは特別な children という props を使い、以下のようにして受け取った子要素を出力することができます。 これにより他のコンポーネントから JSX をネストすることで任意の子要素を渡すことができます。 <FancyBorder> JSX タグの内側のあらゆる要素は FancyBorder に children という props として渡されます。FancyBorder は <div> の内側に {props.children} をレンダーするので、渡された要素が出力されます。 あまり一般的ではありませんが、複数の箇所に子要素を追加したいケースも考えられます。そのようなケースでは以下のように children の props の代わりに独自の props を作成して渡すことができます。 <Contacts /> や <Chat /> のような React の要素はただのオブジェクトなので、他のあらゆるデータと同様に props として渡すことができます。このアプローチは他のライブラリで言うところの slot に似ていると感じるかもしれませんが、React のコンポーネントに props として渡せるものに制限はありません。 特化したコンポーネント (Specialization) コンポーネントを他のコンポーネントの “特別なケース” として考えることがあります。例えば、WelcomeDialog は Dialog の特別なケースがあります。 React ではこれもコンポジションで実現できます。汎用的なコンポーネントに props を渡して設定することで、より特化したコンポーネントを作成することができます。 コンポジションはクラスとして定義されたコンポーネントでも同じように動作します。 継承はどうなの? Facebook では、何千というコンポーネントで React を使用していますが、コンポーネント継承による階層構造が推奨されるケースは全く見つかっていません。 props とコンポジションにより、コンポーネントの見た目と振る舞いを明示的かつ安全にカスタマイズするのに十分な柔軟性が得られます。コンポーネントはどのような props でも受け付けることができ、それはプリミティブ値でも、React … Read more

React講座 state のリフトアップ

react state

しばしば、いくつかのコンポーネントが同一の変化するデータを反映する必要がある場合があります。そんなときは最も近い共通の祖先コンポーネントへ共有されている state をリフトアップすることを推奨します。これを、実際にはどのように行うかを見てみましょう。 この章では、与えられた温度で水が沸騰するかどうかを計算する温度計算ソフトを作成します。 BoilingVerdict というコンポーネントから始めましょう。これは温度を celsius という props として受け取り、水が沸騰するのに十分な温度かどうかを表示します。 次に Calculator と呼ばれるコンポーネントを作成します。温度を入力するための <input> 要素をレンダーし、入力された値を this.state.temperature に保持します。 加えて、現在の入力値を判定する BoilingVerdict もレンダーします。 2 つ目の入力を追加する 新しい要件は、摂氏の入力に加えて、華氏の入力もできるようにして、それらを同期させておくことです。 Calculator から TemperatureInput コンポーネントを抽出するところから始めましょう。props として、”c” もしくは “f” の値をとる scale を新しく追加します: これで Calculator を 2 つの別個の温度入力フィールドをレンダーするように変更することができます: 2 つの入力フィールドが用意できました。しかし、片方に温度を入力しても、もう片方は更新されません。これは要件を満たしていません: 2 つの入力フィールドを同期させたいのです。 Calculator から BoilingVerdict を表示することもできません。Calculator は TemperatureInput の中に隠されている現在の温度を知らないのです。 変換関数の作成 まず、摂氏から華氏に変換するものとその反対のものと、2 つの関数を書きます。 これら 2 つの関数は数字を変換します。次に文字列で表現された temperature と変換関数を引数に取り文字列を返す、別の関数を作成します。この関数を一方の入力の値をもう一方の入力に基づいて計算するのに使用します。 常に値が小数第 3 位までで四捨五入されるようにし、無効な temperature には空の文字列を返します。 例えば、tryConvert(‘abc’, toCelsius) は空の文字列を返し、tryConvert(‘10.22’, toFahrenheit) は ‘50.396’ を返します。 state のリフトアップ 現時点では、両方の TemperatureInput コンポーネントは独立してローカルの state を保持しています: しかし、2 つの入力フィールドはお互いに同期されていて欲しいのです。摂氏の入力フィールドを更新したら、華氏の入力フィールドも華氏に変換された温度で反映されて欲しいですし、逆も同じです。 React での state の共有は、state を、それを必要とするコンポーネントすべての直近の共通祖先コンポーネントに移動することによって実現します。これを “state のリフトアップ (lifting state up)” と呼びます。TemperatureInput からローカルの state を削除して Calculator に移動しましょう。 Calculator が共有の … Read more

react講座 フォーム

react フォーム

HTML のフォーム要素は当然のこととして内部に何らかの状態を持っていますので、フォーム要素は React において他の DOM 要素と少し異なる動作をします。例えば、この HTML によるフォームは 1 つの名前を受け付けます: このフォームは、ユーザがフォームを送信した際に新しいページに移動するという、HTML フォームとしてのデフォルトの動作をします。React でこの振る舞いが必要なら、そのまま動きます。しかし大抵のケースでは、フォームの送信に応答してユーザがフォームに入力したデータにアクセスするような JavaScript 関数があった方が便利ですね。これを実現する標準的な方法は、“制御された (controlled) コンポーネント” と呼ばれるテクニックを使うことです。 制御されたコンポーネント HTML では <input>、<textarea>、そして <select> のようなフォーム要素は通常、自身で状態を保持しており、ユーザの入力に基づいてそれを更新します。React では、変更されうる状態は通常はコンポーネントの state プロパティに保持され、setState() 関数でのみ更新されます。 React の state を “信頼できる唯一の情報源 (single source of truth)” とすることで、上述の 2 つの状態を結合させることができます。そうすることで、フォームをレンダーしている React コンポーネントが、後続するユーザ入力でフォームで起きることも制御できるようになります。このような方法で React によって値が制御される入力フォーム要素は「制御されたコンポーネント」と呼ばれます。 例えば、前述のフォームの例において、フォーム送信時に名前をログに残すようにしたい場合、フォームを制御されたコンポーネントとして書くことができます: フォーム要素の value 属性が設定されているので、表示される値は常に this.state.value となり、React の state が信頼できる情報源となります。handleChange はキーストロークごとに実行されて React の state を更新するので、表示される値はユーザがタイプするたびに更新されます。 制御されたコンポーネントを使うと、ユーザ入力の値は常に React の state によって制御されるようになります。これによりタイプするコード量は少し増えますが、その値を他の UI … Read more