2018年5月22日
プログラミング
Reactでスマートスピーカーのコマンド発音サービスを作ろう(4)【作りながら覚えるReact】
はじめに
Reactでスマートスピーカーの発音サービスを作るシリーズの第4弾です。
前回は発音をするボタンを作り、Propsを渡すことでAlexa、Google Home用のコマンドを実行してくれるように開発しました。
今回は、いくつかのコマンドをファイルにまとめ、そちらをループで発音ボタンとして展開する方法をご紹介します。
完成形はこのようなイメージです。
コマンドデータをファイルにまとめる
前回まではこのように、音楽をかけるコマンドを個別にsrc/components/speaker_button.js
に記載していました。
<div className="col-sm-6 mb-2 mt-2">
<button className="card" onClick={() => this._onClick()}>
<div className="card-body">
<h4 className="card-title text-left">
<i className="fas fa-play"></i>
音楽かけて
</h4>
<p className="card-text text-left">
ランダムで音楽をかけてくれるコマンドです。
</p>
</div>
</button>
</div>
ですが、例えば「音楽かけて」以外に10個とかコマンドを並べたいとき、10個speaker_button.js
内にコマンドを記載していくのは、とても見づらくメンテナンスしづらくなってしまいます。
そこで、コマンド自体を別のファイルにまとめてしまい、そちらをspeaker_button.js
内で展開していくことにしましょう。
今回は、src配下にconst(constant値、つまり定数として変わらない値)ディレクトリを作り、その中にalexa.js
とgoogle.js
というファイルを作ります。
src/const/alexa.js
export const Alexa = {
pre_commands: 'アレクサ、',
commands: [
{
title: '音楽かけて',
pronunciation: 'おんがくかけて',
description: 'ランダムで音楽をかけてくれるコマンドです。',
},
{
title: '音楽とめて',
pronunciation: 'おんがくとめて',
description: '再生中の音楽を停止するコマンドです。',
},
{
title: '音量上げて',
pronunciation: 'おんりょうあげて',
description: '音量を上げてくれるコマンドです。',
},
{
title: '音量下げて',
pronunciation: 'おんりょうさげて',
description: '音量を下げてくれるコマンドです。',
},
{
title: '洋楽流して',
pronunciation: '洋楽ながして',
description: '洋楽をかけてくれるコマンドです。',
},
{
title: 'ジャズ流して',
pronunciation: 'ジャズながして',
description: 'ジャズ音楽をかけてくれるコマンドです。',
},
{
title: 'この曲名を教えて',
pronunciation: 'この曲名を教えて',
description: '現在流れている曲名を教えてくれるコマンドです。',
},
{
title: 'この曲をリピートして',
pronunciation: 'この曲をリピートして',
description: '現在流れている曲をリピート再生してくれるコマンドです。',
},
]
}
src/const/google.js
export const Google = {
pre_commands: 'OK Google、',
commands: [
{
title: '音楽かけて',
pronunciation: 'おんがくかけて',
description: 'ランダムで音楽をかけてくれるコマンドです。',
},
{
title: '音楽とめて',
pronunciation: 'おんがくとめて',
description: '再生中の音楽を停止するコマンドです。',
},
{
title: '音量上げて',
pronunciation: 'おんりょうあげて',
description: '音量を上げてくれるコマンドです。',
},
{
title: '音量下げて',
pronunciation: 'おんりょうさげて',
description: '音量を下げてくれるコマンドです。',
},
{
title: '洋楽流して',
pronunciation: '洋楽ながして',
description: '洋楽をかけてくれるコマンドです。',
},
{
title: 'ジャズ流して',
pronunciation: 'ジャズながして',
description: 'ジャズ音楽をかけてくれるコマンドです。',
},
{
title: 'この曲名を教えて',
pronunciation: 'この曲名を教えて',
description: '現在流れている曲名を教えてくれるコマンドです。',
},
{
title: 'この曲をリピートして',
pronunciation: 'この曲をリピートして',
description: '現在流れている曲をリピート再生してくれるコマンドです。',
},
]
}
AlexaとGoogle Homeではコマンドは異なるものもある為、現時点では全て一緒ですがファイルを分けることにします。
では中身を見ていきます。
export const Alexa = {
export const Google = {
ここではconst変数としてexportしています。
pre_commands
はコマンド実行前の呼びかけの文言ですね。
その下にcommand
で実行するコマンドを配列で格納しています。
項目を見ていきます。
title:
はリストを表示するときの見出し(タイトル)部分です。
pronunciation
はJavaScriptで発音させる項目です。音読み訓読み等、正しく発音してくれない可能性を考えて、私たちが見るようの見出しとJavaScriptで発音させる項目を分けています。
description
は説明部分です。
発音ボタンを展開する
では、これらのconstファイルをspeaker_button.js
内で呼び出していきましょう。
まずimportしていきます。
import {Alexa} from '../const/alexa';
import {Google} from '../const/google';
では、次にconst値を展開していきます。
コマンドを格納していたのはcommands
という配列でしたね。
配列を展開する為には、map
を仕様します。
Alexa.commands.map((command) => {
return (
<div className="col-sm-6 mb-2 mt-2">
<button className="card" onClick={() => this._onClick(command.pronunciation)}>
<div className="card-body">
<h4 className="card-title text-left">
<i className="fas fa-play"></i>
{command.title}
</h4>
<p className="card-text text-left">
{command.description}
</p>
</div>
</button>
</div>
);
})
);
最初のAlexa.commands.map((command) =>
でAlexaのcommandsの中身を展開してcommandに格納しています。
これでcommandのキーであるtitleやdescription、pronunciationを使用し、値を取得することができます。
<button className="card" onClick={() => this._onClick(command.pronunciation)}>
前回までのコードでは発音ボタンでどの発音をするか、特に指定が必要ありませんでした。
ですが、今回はどの発音をするか情報が必要なので、_onClickの引数としてcommandのpronounciationを指定しています。
{command.title}
{command.description}
これらは問題ないですね。commandのtitle、descriptionの値を取り出しています。
さて、今回Alexa.commands
とAlexaを指定しましたが、Googleの場合はGoogle.commands
とする必要がありそうです。
この為にもう一度Google用の処理を書くのは二度手間になりそうです。
なので、今回はこのコンポーネントの初期化処理時に呼び出し元の引数を使用し、Alexa、Googleいずれかの値を格納し、そこからcommandsを展開する形が良さそうです。
constructor
constructorはオブジェクト指向プログラミングをしている方は馴染み深いと思います。
オブジェクト生成時に初期化などを行うメソッドです。
今回の場合、Reactのコンポーネント生成時に呼ばれる初期化用メソッドと考えていただくのが良いです。
早速AlexaとGoogle用のconstructorを書いていきます。
constructor(props) {
super(props);
switch (this.props.speaker_type) {
case 'alexa': {
this.speaker_type = Alexa;
break;
}
case 'google': {
this.speaker_type = Google;
break;
}
default:
break;
}
}
constructor(props)
constructorは引数としてpropsを取ります。
super(props);
superキーワードは親クラス、ここではComponentクラスのコンストラクタを表しています。
Componentクラスを継承するためには、コンストラクタ内で必ず呼び出す必要があります。
POINT!!
今までconstructorやsuper(props)といったものは書かなくても、this.props.hoge とthis.propsを使用できていました。これはなぜでしょうか?
実はconstructorの中身がsuper(props)の場合にはconstructorを省略することができるのです。
さて、super(props)
によってthis.props.speaker_type
でspeaker_typeを取得できるようになりました。
これでcase文を作り、this.speaker_type
にAlexaかGoogleを格納しましょう。
switch (this.props.speaker_type) {
case 'alexa': {
this.speaker_type = Alexa;
break;
}
case 'google': {
this.speaker_type = Google;
break;
}
default:
break;
}
明示的にbreak
を入れるのを忘れないようにしましょう!
これでthis.speaker_typeにAlexaかGoogleかが入るようになりました。
これを使用し、先程のmap部分で使用していきます。
this.speaker_type.commands.map((command)
では、最後に_onClick
部分を修正していきます。
先程、このようにpronunciation
を引数として渡していました。
<button className="card" onClick={() => this._onClick(command.pronunciation)}>
このpronunciation(発音内容)を使用し、発音させていきましょう。
_onClick(pronunciation) {
let ssu = new SpeechSynthesisUtterance();
ssu.text = this.speaker_type.pre_commands + pronunciation;
ssu.lang = 'ja-JP';
speechSynthesis.speak(ssu);
}
特に難しい点はありませんね!
では、speaker_button.jsを通しで見ていきます。
import React, { Component } from 'react';
import {Alexa} from '../const/alexa';
import {Google} from '../const/google';
export default class SpeakerButton extends Component {
constructor(props) {
super(props);
switch (this.props.speaker_type) {
case 'alexa': {
this.speaker_type = Alexa;
break;
}
case 'google': {
this.speaker_type = Google;
break;
}
default:
break;
}
}
_onClick(pronunciation) {
let ssu = new SpeechSynthesisUtterance();
ssu.text = this.speaker_type.pre_commands + pronunciation;
ssu.lang = 'ja-JP';
speechSynthesis.speak(ssu);
}
render() {
return (
Alexa.commands.map((command) => {
return (
<div className="col-sm-6 mb-2 mt-2">
<button className="card" onClick={() => this._onClick(command.pronunciation)}>
<div className="card-body">
<h4 className="card-title text-left">
<i className="fas fa-play"></i>
{command.title}
</h4>
<p className="card-text text-left">
{command.description}
</p>
</div>
</button>
</div>
);
})
);
}
}
これで、今回のイメージは完成ですね!
まとめ
今回はデータをconstファイルに格納し、そちらをmapで展開しました。
またconstructor内で初期化処理としてスピーカーのタイプを格納し、使用する方法も解説しました。
次回はよりUIをリッチにし、stateを使ったレンダリングの使い方を見ていきます。
Reactのお仕事に関するご相談
Bageleeの運営会社、palanではReactに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。
この記事は
参考になりましたか?
0
0
関連記事
2022年5月13日
Reactでオセロゲームを作る
2021年4月9日
Slack OAuth x React で Slack ユーザー認証を作ってみた!
2021年3月1日
Reactで使えるバリデーションライブラリを紹介!
2021年2月22日
Hasura Cloud × Auth0 × React でお手軽にTodoアプリを作ってみた!
2020年12月12日
Blitz.jsとTailwind CSSでメモ帳アプリの作成【第2弾】
2020年12月8日
コンポーネントを実装するときに意識すること
簡単に自分で作れるWebAR
「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。
palanARへpalanでは一緒に働く仲間を募集しています
正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。
運営メンバー
Eishi Saito 総務
SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。
sasakki デザイナー
アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。
やまかわたかし デザイナー
フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。
Sayaka Osanai デザイナー
Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。
はらた エンジニア
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
こぼり ともろう エンジニア
サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。
ささい エンジニア
フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。
Damien
WebAR/VRの企画・開発をやっています。森に住んでいます。
ゲスト bagelee
かっきー
まりな
suzuki
miyagi
ogawa
雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。
いわもと
デザイナーをしています。 好きな食べ物はラーメンです。
taishi kobari
フロントエンドの開発を主に担当してます。Blitz.js好きです。
kubota shogo
サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!
nishi tomoya
aihara
グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。
nagao
SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。
Kainuma
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
sugimoto
asama
ando
iwasawa ayane
yoko oshimo
異業界からやってきたデザイナー。palanARのUIをメインに担当してます。これからたくさん吸収していきます!