- 投稿日:2020-08-23T22:58:07+09:00
Javascript基本②
ボタンをJavaScript上で扱えるようにする
ボタンを押したらコンソール上で「Hello world」と出す実装をしていきます!
DOMという仕組みを利用します。DOMとは
HTMLを解析して、データを作成する仕組みです。
DOMによって解析されたHTMLは階層構造のあるデータです。
これを、DOMツリーもしくはドキュメントツリーと呼びます。JavaScriptを使うと、DOMツリーを操作することができます!
idやclassの情報を元に、DOMツリーの一部を取得して要素を増やしたり消したりします。
このDOMツリーの一部のことをノードオブジェクトと呼びます。ノードとは
DOMツリーを構成する要素をノードと呼びます。
body → ノード
header → ノード
side_bar → ノード
footer → ノードDOMツリーの情報
DOMツリーの情報は検証ツールで見れます。
ノードの取得
1.document.getElementById("id名");
documentは開いているページのDOMツリーが入っているオブジェクト。
ドキュメントに対していくつかのメソッドを使用することで、DOMツリーに含まれる要素を抽出して取得することができます。DOMツリーから特定の要素を取得するためのメソッドの一つです。2.document.getElementsByClassName("class名");
classを指定して取得する場合は上記です。"Elements"と複数形にして利用します。
同じclassを持つ要素を全て取得することができます!3.document.querySelector("セレクタ名");
セレクタ名とは、CSSでスタイルを適用するために指定している要素。
HTML上から、引数で指定したセレクタに合致するもののうち一番最初に見つかった要素1つを取得コンソールでボタン要素を取得
document.querySelector("button");
戻り値は<button id="Button">ボタン</button>
HTMLタグのようなものがノードです。querySelectorメソッド 複雑なセレクタ指定
idがbutton2のbuttonタグの要素
docuent.querySelector("button#Button2");footerタグ要素の中の、クラスがnextのaタグ要素
document.querySelector("footer a.next");上記でquerySelectorメソッドを使って、ボタンをJavaScript上で取得することができます。
querySelectorメソッドでは、複雑なセレクタも指定できます。
今回は以上です!
- 投稿日:2020-08-23T22:34:40+09:00
javascriptで指定した数値の長さを持つArrayの宣言
- 投稿日:2020-08-23T19:20:03+09:00
prototypeと__proto__
Javaに慣れたからちょっと理解しづらかった
prototypeの意味
「原型」という意味である。
Javaのスーパークラス、C++のベースクラスと少し似ている。初心者なりにまとめてみた
インスタンスを生成するためには、コンストラクター関数を使う
例えばObject()、Array()、Function()。これらのコンストラクター関数を持っているのは、
Objectオブジェクト、Arrayオブジェクト、Functionオブジェクトである。
また、それぞれのオブジェクトの中に、prototypeというオブジェクトがある。
prototypeの中に、関数や__proto__などがある。
__proto__は、どこかのprototypeを指すためのポインタみたいなものである簡単にいうと
- 全てのオブジェクトは
__proto__というメンバをもつ- コンストラクター関数を持っているオブジェクトは
prototypeというメンバをもつprototypeの中にも、__proto__があるメンバー関数を呼び出す際に、まずインスタンス内で探す。
なければ、__proto__を通してどこかのprototypeに辿り、その中で関数を探す。
それでも見つからない場合、そのprototype内の__proto__より、新たなprototypeに辿り着く。
こういうふうなループになり、最終的に__proto__===nullになって、undefinedが返される。具体的な関係
出力が全て
trueとなるObject.prototype.__proto__ === null Object.__proto__ === Function.prototype // 生成したインスタンスの__proto__ (new Object()).__proto__ === Object.prototype Function.prototype.__proto__ === Object.prototype Function.__proto__ === Function.prototype // 生成したインスタンスの__proto__ (new Function()).__proto__ === Function.prototype Array.prototype.__proto__ === Object.prototype Array.__proto__ === Function.prototype // 生成したインスタンスの__proto__ (new Array()).__proto__ === Array.prototype参考記事
図で理解するJavaScriptのプロトタイプチェーン
JavaScriptのプロトタイプチェーンを深堀りする
JavaScript のプロトタイプを理解する
JavaScriptのプロトタイプからオブジェクト指向を学ぶ
- 投稿日:2020-08-23T19:13:05+09:00
【onClick属性】個性のあるボタンをクリックして、イベント発生させる【JavaScript】
要素をクリックしたら、関数を発生させる
// 基本形 <input onClick="関数()">いくつかあるボタンの中でも、ナンバー1の確認ボタンを押した時の挙動を設定する
<input type="button" onClick="kakunin(1)"> <input type="button" onClick="kakunin(2)"> <input type="button" onClick="kakunin(3)">function kakunin(number){ if(number == 1){ location.html = "/users" } }ナンバー1の確認ボタンをクリックした時だけ、/usersに飛ぶように設定できる
DOM操作によって生まれた要素に、個性を与える
生み出されたボタンごとに、イベント内容を変えたいときに使える。
jQueryattr('onClick', 'openDialog(kakunin.id)')openDialog()の引数が変わるので、それぞれ取得できる。
- 投稿日:2020-08-23T18:32:26+09:00
オレオレJavaScript/TypeScriptコードスニペット集
- 投稿日:2020-08-23T17:58:53+09:00
みんな大好き「バリデーション」。コロナでどこへも行けませんが,画面にマスク着用すると,開発がちょっとだけ幸せになるかもという余談
概要
台湾しかり,ベトナムしかり。
コロナ対策で成功している国を見ると,早期の歯止めが,共通因数だなぁと感じるおじさんです。
システム開発の現場でも,早期の歯止めが,開発を幸せにしてくれるということを,記事にしてみようと思います。
具体的には,みんな大好き「バリデーション」関連です。
みんな大好き「バリデーション」
システム開発工程が無事完了し,いざ,利用部門ユーザを巻き込んだテストの段になって,意外と多いのが,誤入力防止機能(バリデーション)を,追加開発リクエストされるという展開。
「この欄は,過去日付が入力されたら,エラーメッセージを出して欲しい」
一般的な傾向として,完成したシステム画面を,実際に操作してみると,利用部門の期待(と欲望)は,ぐーんと高まるのですが,これは,人間として,ごく自然な心理特性です(=人間,何かを手に入れたら,もっと良いものが欲しくなる)。
特に,「品質の作り込み」が大好きな日本国内のシステム導入では,テスト工程での「後出しじゃんけん」って,驚くほど,お盛んですよね。
言葉がまったく通用しない地域を含めて,過去,六か国でのシステム導入を経験したおじさんですが,ぶっちゃけ,一番消耗したのは日本導入でした(ヒソヒソ)。
要求を無下にはねのけると,良好な人間関係に亀裂が走ることもありますが,Yes マンになってしまうと,要求がエスカレートし,プロジェクトをうまくコントロールできなくなるリスクもあり,プロマネとして,難しいかじ取りを迫られることもあります。
軽く済ませたい,フロントエンド側での実装作業
バリデーション実装となれば,大きく分けて,二つのアプローチがあります:
- フロントエンド(例:JavaScript)でのバリデーション実装
- バックエンド(例:PHP)でのバリデーション実装
システムって,誤入力はもちろんのこと,悪意のこもった入力まで,きちんと想定しなければならないため,DB 書込処理と近い距離にある,バックエンドのバリデーション実装は必須と言って良いと思います。
問題は,フロントエンドでのバリデーション実装。
どうせ,最終的にはバックエンド側でバリデーションを通すことになるのだから,フロントエンドは,できるだけ,手軽な実装方式で済ませたいというのが,多くの開発者での,共通認識ではないでしょうか?
きちんと作り込んだシステムって,データを入れて,入力欄からフォーカスアウトするごとに,律義にエラーチェック(それも,サーバとの通信を要する,高度なもの)がかかったりしますが,あれをすべての入力欄でやったら,死にます(おじさんは)。
定番スタイルとして確立された実装技術
それでは,フロントエンドでのバリデーションを,簡易的に済ませるには,どのようなアプローチがあるでしょうか?
データ型によっては,すでに,コスパよき実装手法が確立されたものもあります:
- 日付型 カレンダー(例:DatePicker)経由でのみ入力を許可。手入力は禁止
- 文字型
maxlength指定によって,上限文字数を制限- 論理型
<input type="checkbox">の利用入力欄そのものを,正しいパターンしか反応させなくするという,物理的に封じるアプローチ。
また,「性別」や「都道府県」など,リスト化が容易な入力欄は,
<select></select>を使えば,予期せぬ値がバックエンドに送られることを,未然防止できます。これらは,いずれも手軽に実装できるものであり,エンドユーザにとっても,入力ミスを回避できるため,ユーザフレンドリーな UI であると言えます。
もうひとひねり,フロントエンドでの実装作業
一方,数字や電話番号,郵便番号,メールアドレスといった「データ型」の話になると,汎用的な実装手法について,あまり活発に議論されていない印象があります。
こういった「データ型」は,システム仕様によって,求められるチェック条件が変わる(例:郵便番号は,国によって,桁数が異なります)ため,一般論として語りづらいという背景はあるにせよ,システム開発の現場では,頻出する「データ型」であることに変わりありません。
ケースバイケースですが,「テキストマスク」を使うと,幸せになれる案件だって,結構あるかも知れないので,ご紹介します。
画面にも「マスク」着用しよう
バリデーションと比べると,認知度は低くなるのですが,入力欄の書式をチェックする「テキストマスク」を採用するというアプローチもあります。
ブラウザの JavaScript 上で動作するもので,いろいろなライブラリが出回っていますが,参考として 'Vanilla Text Mask' を取り上げます:
公式サイト:vanilla-text-mask
以下,いくつかの事例を取り上げます。
実装事例① 「郵便番号」欄
テキストマスク 'Vanilla Text Mask' は,正規表現と,JavaScript の文法(配列)をミックスさせた書き方が特徴的です。
ここでは,「数値3ケタ ハイフン 数値4ケタ」という,日本の郵便番号を取り上げてみましょう。
実装作業は,JS ファイルで
[/\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]というマスクを指定し,入力欄とバインドするだけ。第一印象では,正規表現と,JavaScript の文法(配列)が入り混じっているため,頭にクエスチョンマークが浮かびそうになりますが,普通の JavaScript の文法(配列)と解釈すれば,恐れるに足りません。
これによって,キーボードからの入力が制約できるようになり,
123-4567と入れれば反応しますが,abc-defgや123456とタイプすれば,何事も起こらなかったかのように,無反応になります(キーボードの入力値をはねのけます)。index.html<input type="text" id="postal_code">postal_code_mask.jsconst postal_code_mask = [/[\d]/, /\d/, /\d/, '-', /[\d]/, /\d/, /\d/, /\d/] const postal_code = document.querySelector('#postal_code') vanillaTextMask.maskInput({ inputElement: postal_code, mask: postal_code_mask })実装事例② 「年齢」欄
次は,年齢欄を題材にしてみましょう。
たとえば,未成年が利用しないシステム(年齢の幅:20 ~ 99)だと,JS ファイルで
[/[2-9]/, /[0-9]/]というマスクを指定し,入力欄とバインドするだけで完了。これによって,キーボードからの入力が制約できるようになり,
23と入れれば反応しますが,abや12とタイプすれば,何事も起こらなかったかのように,無反応になります。index.html<input type="text" id="age">age_mask.jsconst age_mask = [/[2-9]/, /[0-9]/] const age = document.querySelector('#age') vanillaTextMask.maskInput({ inputElement: age, mask: age_mask })まとめ
以上,「テキストマスク」による,フロントエンドの誤入力防止アプローチをご紹介しました。
サーバとの通信が求められず,かつ,書式が固定されているようなケースでは,フロントエンド上で実装が完結するので,つぶしの効きやすい技術であると言えます。
(ほぼ)すべてのブラウザの種類やバージョンで正常動作する,クロスブラウザ対応をしてくれているのも,嬉しいポイントですね。
締めくくる前に,もう一度強調したいと思いますが,バリデーション実装のキモは,やはり,バックエンド側(理想的には DB 書込直前タイミング)での最終チェック。
そして,バリデーションって,足せば足すほど望ましいというわけでもなく,システム開発予算とのバランスもありますし,場合によっては,バッサリ省略するという,思い切ったアプローチを視野に入れることも大切です:
- 人間の手入力が介在しないデータ入力(例:他システムからデータを受け取るケースなど)
- 社内ネットワーク内でのみ提供され,利用人数が非常に少ない簡易的システム
フロントエンドとバックエンドで,バリデーション処理の一部を共通化して,開発工数を節約するのも一案。
このトピック周辺って,いくら語っても,語りつくせない,奥深き世界ですが,本記事によって,「テキストマスク」と出会い,幸せになれるエンジニアが一人でもいらっしゃったら,おじさんの苦労がすべて報われます。
- 投稿日:2020-08-23T17:23:32+09:00
P5.js 日本語リファレンス(unhex)
このページでは「P5.js 日本語リファレンス」 の unhex 関数を説明します。
unhex()
説明文
16進数の文字列表現を同等の整数値に変換します。 16進表記の文字列の配列が渡されると、同じ長さの整数の配列が返されます。
構文
unhex(n)
unhex(ns)
パラメタ
n
String:変換する値ns
Array:変換する値戻り値
Number:16進値の整数表現
例1
print(unhex('A')); // 10 print(unhex('FF')); // 255 print(unhex(['FF', 'AA', '00'])); // [255, 170, 0]著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-23T17:23:23+09:00
P5.js 日本語リファレンス(unchar)
このページでは「P5.js 日本語リファレンス」 の unchar 関数を説明します。
unchar()
説明文
単一文字の文字列を対応する整数表現に変換します。単一文字の文字列値の配列が渡されると、同じ長さの整数の配列が返されます。
構文
unchar(n)
unchar(ns)
パラメタ
n
String:変換する値ns
Array:変換する値戻り値
数値:値の整数表現
例1
print(unchar('A')); // 65 print(unchar(['A', 'B', 'C'])); // [65, 66, 67] print(unchar(split('ABC', ''))); // [65, 66, 67]著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-23T17:23:13+09:00
P5.js 日本語リファレンス(str)
このページでは「P5.js 日本語リファレンス」 の str 関数を説明します。
str()
説明文
ブール、文字列、または数値をその文字列表現に変換します。値の配列が渡されると、同じ長さの文字列の配列が返されます。
構文
str(n)
パラメタ
- n
String | Boolean | Number | Array:変換する値戻り値
String:値の文字列表現
例1
print(str('10 ')); // '10' print(str(10.31)); // '10.31' print(str(-10)); // '-10' print(str(true)); // 'true' print(str(false)); // 'false' print(str([true, '10 .3 ', 9.8])); // ['true', '10.3', '9.8']著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-23T17:23:01+09:00
P5.js 日本語リファレンス(int)
このページでは「P5.js 日本語リファレンス」 の int 関数を説明します。
int()
説明文
ブール値、文字列、または浮動小数点数をその整数表現に変換します。値の配列が渡されると、同じ長さのint配列が返されます。
構文
int(n, [radix])
int(ns)
パラメタ
n
String | Boolean | Number:変換する値radix
Number:変換する基数(デフォルト:10)(オプション)ns
Array:変換する配列戻り値
数値:値の整数表現
例1
print(int('10 ')); // 10 print(int(10.31)); // 10 print(int(-10)); // -10 print(int(true)); // 1 print(int(false)); // 0 print(int([false, true, '10 .3 ', 9.8])); // [0, 1, 10, 9] print(int(Infinity)); //Infinity print(int('-Infinity')); //-Infinity著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-23T17:22:50+09:00
P5.js 日本語リファレンス(hex)
このページでは「P5.js 日本語リファレンス」 の hex 関数を説明します。
hex()
説明文
数値を同等の16進表記の文字列に変換します。 2番目のパラメタ digits は、変換する16進表記の文字列の文字数を設定します。配列が渡されると、同じ長さの16進表記の文字列の配列が返されます。
構文
hex(n, [digits])
hex(ns, [digits])
パラメタ
n
Number:変換する値digits
Number:変換する16進表記の文字列の文字数(オプション)ns
Number[]:変換する値の配列戻り値
String:値の16進数の文字列表現
例1
print(hex(255)); // "000000FF" print(hex(255, 6)); // "0000FF" print(hex([0, 127, 255], 6)); // ["000000", "00007F", "0000FF"] print(Infinity); // "FFFFFFFF" print(-Infinity); // "00000000"著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-23T17:22:36+09:00
P5.js 日本語リファレンス(float)
このページでは「P5.js 日本語リファレンス」 の float 関数を説明します。
float()
説明文
文字列をその浮動小数点表現に変換します。文字列の内容は数値に似ている必要があります。そうでない場合、NaN(数値ではない)が返されます。たとえば float("1234.56")は 1234.56 と評価されますが, float("giraffe")は NaN を返します。
値の配列が渡されると、同じ長さの浮動小数点数の配列が返されます。
構文
float(str)
パラメタ
- str
String:変換する浮動文字列戻り値
Number:文字列の浮動小数点表現
例1
print(float('10 .31 ')); // 10.31 print(float('Infinity')); //Infinity print(float('-Infinity')); //-Infinity著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-23T17:22:23+09:00
P5.js 日本語リファレンス(char)
このページでは「P5.js 日本語リファレンス」 の char 関数を説明します。
char()
説明文
数値または文字列を対応する単一文字の文字列表現に変換します。文字列パラメータが指定されている場合、最初に整数として変換され、次に1文字の文字列に変換されます。数値または文字列値の配列が渡されると、同じ長さの単一文字の文字列の配列が返されます。
構文
char(n)
char(ns)
パラメタ
n
String | Number:変換する値ns
Array:変換する配列戻り値
String:値の文字列表現
例1
print(char(65)); //「A」 print(char('65 ')); //「A」 print(char([65, 66, 67])); // ["A", "B", "C"] print(join(char([65, 66, 67]), '')); // 「ABC」著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-23T17:22:12+09:00
P5.js 日本語リファレンス(byte)
このページでは「P5.js 日本語リファレンス」 の byte 関数を説明します。
byte()
説明文
数値、数値の文字列表現、またはブール値をそのバイト表現に変換します。 1バイトは -128 から 127 までの整数にしかできないため、この範囲外の値が変換されると対応するバイト表現に折り返されます。数値、文字列、またはブール値の配列が渡されると同じ長さのバイトの配列が返されます。
構文
byte(n)
byte(ns)
パラメタ
n
String | Boolean | Number:変換する値ns
Array:変換する配列戻り値
Number:値のバイト表現
例1
print(byte(127)); // 127 print(byte(128)); // -128 print(byte(23.4)); // 23 print(byte('23 .4 ')); // 23 print(byte('hello')); // NaN print(byte(true)); // 1 print(byte([0, 255, '100'])); // [0, -1, 100]著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-23T17:21:56+09:00
P5.js 日本語リファレンス(boolean)
このページでは「P5.js 日本語リファレンス」 の boolean を説明します。
boolean
説明文
boolean は、JavaScript の7つのプリミティブデータ型の1つです。 ブール値は true(真) または false(偽) のみです。
MDNエントリから:ブール論理エンティティを表し、2つの値を持つことができます:true(真) または false(偽)
構文
boolean
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-23T15:51:59+09:00
【JavaScript】同じ要素をn回繰り返した配列を作成する
期待結果
const input = ['a', 'b', 'c'] const count = 2 const output = // ? // このような出力が欲しい console.log(output) // => [ ['a', 'b', 'c'], ['a', 'b', 'c'] ]結論
const input = ['a', 'b', 'c'] const count = 2 const output = Array.from({ length: count }, () => input) // (2020/08/23 17:30 追記)または const output = Array(count).fill(input)ハマった例
C# の
Enumerable.Range().Select()と同じノリでnew Array().map()を使って実装しようとしたところ上手くいかなかったC#var input = new[] { "a", "b", "c" }; var count = 2; var output = Enumerable.Range(0, count).Select(index => input);JavaScriptconst input = ['a', 'b', 'c'] const count = 2 // 上記C#のコードと同じ発想 const output = new Array<string>(count).map((_, index) => input) // なぜかこうなる(※コメント欄に解説あり) console.log(JSON.stringify(output)) // => [null, null, null] // mapの前にfillを噛ませるとうまくいく const output = new Array<string>(count).fill().map((_, index) => input) // => [ ['a', 'b', 'c'], ['a', 'b', 'c'] ]
- 投稿日:2020-08-23T15:47:55+09:00
vue.js 日付指定ライブラリ vuejs-datepickerで選択可能日付を制限する
本記事について
vuejs-datepicker のライブラリ取得方法等、基本的な情報については省略します。
今回はvuejs-datepickerで選択できる日付を制限する方法を記載します。
vuejs-datepickerで選択可能日付を制限する
テンプレートに、
:disabled-dates="disabledDates"を設定<template> ... <datepicker :disabled-dates="disabledDates"></datepicker> ... </template>script内で、
disabledDatesを指定する<script> data() { return { disabledDates: { to: new Date(), // 本日以前の日付は選択不可 from: new Date(), // 本日以降の日付が選択不可 days: [6, 0], // 曜日指定(この場合、土曜日・日曜日選択不可) daysOfMonth: [29, 30, 31], // 各月の29、30、31日が選択不可 dates: [ // 選択不可の日付を複数指定 new Date(2020, 8, 23), new Date(2020, 8, 24), new Date(2020, 8, 25) ], ranges: [{ // 選択不可の期間を指定 from: new Date(2020, 9, 1), to: new Date(2020, 9, 15) }], } } } </script>
- 投稿日:2020-08-23T15:44:48+09:00
クリックイベントで<label> と チェックボックス、テキストを動的に生成する【JavaScript】
今回、実装したかったのはコチラ
当初、
<input type= checkbox>と<label>テキスト</label>が別々に生成され、紐付けもされず苦労した。そこでまず、
<label>に<input>を追加次に
<input>に<textnode>を追加出来上がった
<label>を<li>に追加するという手順を踏んで実装。
【HTML】
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>To do リスト</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <div class="To-do-list"> <h1>To do リスト</h1> <h2 id="today"></h2> <input type="text"> <button>追加</button> <button id="done">完了</button> <ul> <!-- <li><label><input type="checkbox">買い物</label></li> <li><label><input type="checkbox">読書</label></li> <li><label><input type="checkbox">犬の散歩</label></li> --> </ul> </div> <script src ="js/main.js"></script> </body> </html>【CSS】
body { background: #a1d8e2; } h1 { font-size: 20px; } h2 { font-size: 15px; } .To-do-list { width: 500px; margin: 20px ; } ul { margin-top: 30px; padding: 0; } li { list-style: none; user-select: none; } input[type='checkbox'] { margin-right: 15px; }【JavaScript】
'use strict'; { //------------------------------今日の日付を取得-------------------------------------// let date = new Date(); let month = date.getMonth() + 1; let year = date.getFullYear(); let day = date.getDate(); document.getElementById("today").textContent = `${year}年${month}月${day}日`; //-----------------------------------End-----------------------------------------// //====================== クリックイベント 追加=================================// document.querySelector('button').addEventListener('click', () => { const li = document.createElement('li'); const text = document.querySelector('input'); //html内のinput を選択 const label = document.createElement('label'); const input = document.createElement('input');//新たにinputを生成 input.type = 'checkbox'; const ul = document.querySelector('ul'); li.appendChild(label); label.appendChild(input); label.appendChild(document.createTextNode(`${text.value}`)); ul.appendChild(li);//labelにinputを追加した後、textnodeを追加。 //その出来上がったlabelをliに追加してulに追加するということを実行 text.value = ''; text.focus(); }); //======================================End==========================================// //||||||||||||||||||||||||| クリックイベント 削除|||||||||||||||||||||||||||||||||||||||||||// document.getElementById('done').addEventListener('click', () => { const fineshed = document.querySelectorAll('li')[0]; //完了ボタンをクリックしたら、一番上のliが削除される fineshed.remove(); }); } //||||||||||||||||||||||||||||||||||End||||||||||||||||||||||||||||||||||||||||||||||//
- 投稿日:2020-08-23T15:22:05+09:00
[JavaScript] サンプル動かしてしっかり学ぶ[Promise async/await]徹底入門、組み合わせて使う方法、執筆中
はじめに
現代的な JavaScript には非同期処理という並列(並行?)動作の制御構文としてPromise async/await があります。
これは、フロントのJavaScriptからサーバーに情報を取得するためにAPIを呼び出してそのレスポンスを待機して、レスポンスを受け取った後に、動作を変化させるという、よく使われる処理を行うときに使われるものです。
多用されるにも関わらず簡単とは言い難い構文をしているので、しっかり学んでおくことが大事です。そして、しっかり学べば強い武器になります。
そういうわけで、これらをサンプルを動かしながら理解していきます。
この記事の最後に1ファイルのコードを掲載しておきます。記事内容で使うサンプルは、この1ファイルで全てです。ですので、その最後のコードをコピペして動かしながら試していくとよりわかりやすいかと思います。最後のコード以外は部分的な抜粋です。
setTimeoutを使った非同期処理
まず、Promise も async/await も無しで setTimeout を使った非同期処理を示します。後からこれにPromiseで覆い被せていきます。
このsetTimeoutの処理の理解は多分簡単です。
const randomInt = (min, max) => { return Math.floor( Math.random() * (max + 1 - min) ) + min; }; const testFunc_setTimeout = (name) => { const interval = randomInt(1, 10); setTimeout(() => { console.log(`testFunc_setTimeout name:${name} interval:${interval}`) }, interval); } const main_setTimeout = () => { testFunc_setTimeout('A'); testFunc_setTimeout('B'); testFunc_setTimeout('C'); testFunc_setTimeout('D'); testFunc_setTimeout('E'); testFunc_setTimeout('F'); } main_setTimeout(); // 実行結果 // testFunc_setTimeout name:E interval:2 // testFunc_setTimeout name:C interval:3 // testFunc_setTimeout name:B interval:5 // testFunc_setTimeout name:F interval:6 // testFunc_setTimeout name:A interval:9 // testFunc_setTimeout name:D interval:10randomInt は、指定範囲の乱数を返す関数なので、randomInt(1, 10)とすると、1から10の整数をランダムに返します。
testFunc_setTimeout の内部で、1~10のミリ秒を待機するかを乱数で決めて、待機して、console.logに出力をしています。ですので、出力結果は、ABCDEFの順番にはなりません。
こういう風に書いた順番どおりに実行されない、というのが「同期」していないので「非同期」と呼ばれます。
「同期=synchronous=sync」「非同期=asynchronous=async」となり、Aがつくかつかないかで逆の意味になる英単語となります。
setTimeoutを使った非同期処理でcallback関数で順次実行する
setTimeoutを使った処理を順次実行したいときはこのようにします。まだ Promise async/await は使わないです。
const testFunc_setTimeoutCallback = (name, callback) => { const interval = randomInt(1, 10); setTimeout(() => { console.log(`testFunc_setTimeoutCallback name:${name} interval:${interval}`); callback(); }, interval); } const main2 = () => { testFunc_setTimeoutCallback('A', () => { testFunc_setTimeoutCallback('B', () => { testFunc_setTimeoutCallback('C', () => { testFunc_setTimeoutCallback('D', () => { testFunc_setTimeoutCallback('E', () => { testFunc_setTimeoutCallback('F', () => {}); }); }); }); }); }); } // const main2 = () => { // testFunc_setTimeoutCallback('A', () => { // testFunc_setTimeoutCallback('B', () => { // testFunc_setTimeoutCallback('C', () => { // testFunc_setTimeoutCallback('D', () => { // testFunc_setTimeoutCallback('E', () => { // testFunc_setTimeoutCallback('F', () => {}); // });});});});}); // } main2(); // 実行結果 // testFunc_setTimeoutCallback name:A interval:2 // testFunc_setTimeoutCallback name:B interval:3 // testFunc_setTimeoutCallback name:C interval:4 // testFunc_setTimeoutCallback name:D interval:6 // testFunc_setTimeoutCallback name:E interval:3 // testFunc_setTimeoutCallback name:F interval:7console.log実行後に callback で指定した関数を実行しています。
ですので、実行順番はABCDEFになります。
このサンプルのように多段階の非同期処理がつながるとインデントが深くなりすぎるという問題があります。
インデントが深くならないようにむりやりインデントを消してみたコードも載せておきます。最後のかっこを閉じていくところは、セミコロンも書きましたがセミコロン省略したとしても、けっこう不自然感がありますね。
インデントが深くなりすぎるという問題は、コールバック地獄、というように呼ばれたりもしますが、結構シンプルな構造です。
この後に続く、Promise async/await の方が構文自体が複雑で使いこなすのが難しく、使いこなせていない人が書いた コールバックやPromise async/awaitがごちゃまぜのスパゲッティーコードをみたりすると、これは「コールバック地獄より、async/await地獄の方が闇が深くよほど苦しみがあるな」と感じるコードを見かけたりもしますので、コールバックは地獄で悪者、Promise async/awaitは天国で正義、とは全然呼べないよな、というのが私の実感です。
コールバックの仕組みも理解した上で、Promise async/await もしっかり理解してくると、どちらを使ったにせよシンプルで読みやすいコード書けるようになります。完全理解すれば、物事はよりシンプルになりますので、コールバックでも Promise async/awaitでも、地獄に陥らないようによく学んでおくとよいと思います。
次は上記のコードを、Promise 化していきます。async/awaitはもう少し先です。
Promiseをつかって非同期処理を待機する
次は Promise を使って非同期処理を制御していきます。
const testFunc_Promise = (name) => { const interval = randomInt(1, 10); return new Promise((resolve) => { setTimeout(() => { console.log(`testFunc_Promise name:${name} interval:${interval}`) resolve(); }, interval); }); } const main_Promise = () => { testFunc_Promise('A').then(() => { testFunc_Promise('B').then(() => { testFunc_Promise('C').then(() => { testFunc_Promise('D').then(() => { testFunc_Promise('E').then(() => { testFunc_Promise('F') }) }) }) }) }); } main_Promise(); // 実行結果 // testFunc_Promise name:A interval:9 // testFunc_Promise name:B interval:10 // testFunc_Promise name:C interval:1 // testFunc_Promise name:D interval:1 // testFunc_Promise name:E interval:10 // testFunc_Promise name:F interval:6testFunc_Promise で、
return new Promiseという記述でPromise オブジェクトを生成して、それを戻り値として返しています。Promiseオブジェクトの内部では
(resolve) => { ... resolve() }という記述で、resolveを呼び出すことで完了となります。このresolveは、Promise使用時のreturn と同じようなものと考えるとよいです。main_Promiseの方では、戻ってきた Promise オブジェクトは、.thenというメソッドを持つので、その中に次の処理を記載します。
thenの内部は、resolveが呼ばれた後に動作するようになるので、非同期処理を順番に実行することができます。
thenの内部関数はコールバック関数と同じように動くので、この書き方だとPromiseオブジェクト使用側の記載はコールバック関数で書くのと似た感じになります。
次は別の書き方を紹介します。
Proimseの.thenを連続で記述する
Promiseオブジェクトを返す、testFunc_Promise関数側は修正せずに、呼び出し側のコードを変更します。
const main_PromiseThenThen = () => { testFunc_Promise('A').then(() => { return testFunc_Promise('B'); }).then(() => { return testFunc_Promise('C'); }).then(() => { return testFunc_Promise('D'); }).then(() => { return testFunc_Promise('E'); }).then(() => { testFunc_Promise('F'); }); } // main_PromiseThenThen(); // 実行結果 // testFunc_Promise name:A interval:3 // testFunc_Promise name:B interval:8 // testFunc_Promise name:C interval:4 // testFunc_Promise name:D interval:6 // testFunc_Promise name:E interval:2 // testFunc_Promise name:F interval:8
testFunc_Promise().then(...).then(...)の形式で、thenのメソッドチェーンとして書いています。これで、インデントのネストが深くならないで記述することができます。
また、then内部の関数の中で、return で次に呼び出されているPromiseオブジェクトを返しています。
上記コードは Arrow関数式の省略記法で次のようにも書けます。
const main_PromiseThenThenArrow = () => { testFunc_Promise('A').then( () => testFunc_Promise('B') ).then( () => testFunc_Promise('C') ).then( () => testFunc_Promise('D') ).then( () => testFunc_Promise('E') ).then( () => testFunc_Promise('F') ); } main_PromiseThenThenArrow(); // 実行結果 // testFunc_Promise name:A interval:3 // testFunc_Promise name:B interval:8 // testFunc_Promise name:C interval:4 // testFunc_Promise name:D interval:6 // testFunc_Promise name:E interval:2 // testFunc_Promise name:F interval:8このときに気をつけなければいけないのは、then内部の関数で、returnでPromiseオブジェクトを返さなければ、実行順番がABCDEFにならなくなる、ということです。
繰り返しになりますが、下記のように書くことで「Promiseオブジェクトを返す関数2」の実行を待機した後に「処理2」が実行されます。
Promiseオブジェクトを返す関数1().then(() => { /* 処理1 */ return Promiseオブジェクトを返す関数2() }).then(() => { /* 処理2 */ });ここで、下記のように書いてしまうと待機処理されないので「Promiseオブジェクトを返す関数2」が実行されて、処理が終わるのを待たずに「処理2」は実行されてしまう、ということになります。気をつけてください。
Promiseオブジェクトを返す関数1().then(() => { /* 処理1 */ Promiseオブジェクトを返す関数2() }).then(() => { /* 処理2 */ });待機実行が行われない記載の例も書いておきます。
const main_PromiseThenThenMiss = () => { testFunc_Promise('A').then( () => { testFunc_Promise('B') } ).then( () => testFunc_Promise('C') ).then( () => testFunc_Promise('D') ).then( () => testFunc_Promise('E') ).then( () => testFunc_Promise('F') ); } main_PromiseThenThenMiss(); // 実行結果 // testFunc_Promise name:A interval:10 // testFunc_Promise name:C interval:3 // testFunc_Promise name:B interval:4 // testFunc_Promise name:D interval:6 // testFunc_Promise name:E interval:6 // testFunc_Promise name:F interval:8return がないだけで、Bを待機した後にCが実行される、のではなく、Cの方が先に実行される、という動作になっています。
ここがPromiseの動作を制御するときにミスをしやすいポイントになります。
Promiseオブジェクト関数で戻り値を受け取る
執筆中
Promiseオブジェクト関数で戻り値によって処理を分岐する
執筆中
Promiseオブジェクト関数をasync/awaitをつかって制御する
執筆中
Promiseオブジェクトの.then内関数でasync/awaitを使う
執筆中
Promiseオブジェクト関数をasync/awaitでラップしてから、thenで制御する
執筆中
Promiseオブジェクト関数をasync/awaitでラップしてから、async/awaitで制御する
執筆中
async関数内で、Promiseオブジェクト関数をそのままreturnする
執筆中
async関数内で、Promiseオブジェクト関数をawaitつけてreturnする
執筆中
async関数内で、Promiseオブジェクト関数をawait無しで実行し別の値をreturnする
執筆中
まとめ
Promise まとめ
- Promise オブジェクトは resolve を呼び出して終了する。
- Promise オブジェクトは、.thenメソッドを持つ。 このメソッドの戻り値も Promise オブジェクトを返すので .then().then()の形式で記載が可能になる。
- Promise オブジェクトは resolve(値) で戻り値的なものを返すことができる
- Promise オブジェクトは .then((値) => {})の形式で戻り値的なものを受け取り処理することができる。
- .then内関数で、return で値を返すと次の.thenの関数引数になる。 .then(() => { return 'a' }).then((value)=> { }) これで value は 'a' となる。
- .then内関数で、return でPromiseオブジェクトを返すと、待機した上で次の.thenを呼び出す。 .then(() => { return promissFunc() }).then((value)=> { }) これで value は promissFunc()の戻り値的なものを受け取ることになる。
async/await まとめ
- Promise オブジェクトを返す関数は await で待機することができる。
- await を記載できるのは async 関数だけ
- async 関数は普通に呼び出すと Promise オブジェクトを返す
- await は Promise オブジェクトでの戻り値的なものを取得することができる。
ソースコード一式
こちらがこの記事で使ったコード一式です。
main_xxxの実行部分をコメント解除して動作確認してください。
index.js// -------------------- const randomInt = (min, max) => { return Math.floor( Math.random() * (max + 1 - min) ) + min; }; const testFunc_setTimeout = (name) => { const interval = randomInt(1, 10); setTimeout(() => { console.log(`testFunc_setTimeout name:${name} interval:${interval}`) }, interval); } const main_setTimeout = () => { testFunc_setTimeout('A'); testFunc_setTimeout('B'); testFunc_setTimeout('C'); testFunc_setTimeout('D'); testFunc_setTimeout('E'); testFunc_setTimeout('F'); } // main_setTimeout(); // 実行結果 // testFunc_setTimeout name:E interval:2 // testFunc_setTimeout name:C interval:3 // testFunc_setTimeout name:B interval:5 // testFunc_setTimeout name:F interval:6 // testFunc_setTimeout name:A interval:9 // testFunc_setTimeout name:D interval:10 // -------------------- const testFunc_setTimeoutCallback = (name, callback) => { const interval = randomInt(1, 10); setTimeout(() => { console.log(`testFunc_setTimeoutCallback name:${name} interval:${interval}`); callback(); }, interval); } const main_setTimeoutCallback = () => { testFunc_setTimeoutCallback('A', () => { testFunc_setTimeoutCallback('B', () => { testFunc_setTimeoutCallback('C', () => { testFunc_setTimeoutCallback('D', () => { testFunc_setTimeoutCallback('E', () => { testFunc_setTimeoutCallback('F', () => {}); }); }); }); }); }); } // const main_setTimeoutCallback = () => { // testFunc_setTimeoutCallback('A', () => { // testFunc_setTimeoutCallback('B', () => { // testFunc_setTimeoutCallback('C', () => { // testFunc_setTimeoutCallback('D', () => { // testFunc_setTimeoutCallback('E', () => { // testFunc_setTimeoutCallback('F', () => {}); // });});});});}); // } // main_setTimeoutCallback(); // 実行結果 // testFunc_setTimeoutCallback name:A interval:2 // testFunc_setTimeoutCallback name:B interval:3 // testFunc_setTimeoutCallback name:C interval:4 // testFunc_setTimeoutCallback name:D interval:6 // testFunc_setTimeoutCallback name:E interval:3 // testFunc_setTimeoutCallback name:F interval:7 // -------------------- const testFunc_Promise = (name) => { const interval = randomInt(1, 10); return new Promise((resolve) => { setTimeout(() => { console.log(`testFunc_Promise name:${name} interval:${interval}`) resolve(); }, interval); }); } const main_Promise = () => { testFunc_Promise('A').then(() => { testFunc_Promise('B').then(() => { testFunc_Promise('C').then(() => { testFunc_Promise('D').then(() => { testFunc_Promise('E').then(() => { testFunc_Promise('F') }) }) }) }) }); } // main_Promise(); // 実行結果 // testFunc_Promise name:A interval:9 // testFunc_Promise name:B interval:10 // testFunc_Promise name:C interval:1 // testFunc_Promise name:D interval:1 // testFunc_Promise name:E interval:10 // testFunc_Promise name:F interval:6 // -------------------- const main_PromiseThenThen = () => { testFunc_Promise('A').then(() => { return testFunc_Promise('B'); }).then(() => { return testFunc_Promise('C'); }).then(() => { return testFunc_Promise('D'); }).then(() => { return testFunc_Promise('E'); }).then(() => { testFunc_Promise('F'); }); } // main_PromiseThenThen(); // 実行結果 // testFunc_Promise name:A interval:3 // testFunc_Promise name:B interval:8 // testFunc_Promise name:C interval:4 // testFunc_Promise name:D interval:6 // testFunc_Promise name:E interval:2 // testFunc_Promise name:F interval:8 // -------------------- const main_PromiseThenThenArrow = () => { testFunc_Promise('A').then( () => testFunc_Promise('B') ).then( () => testFunc_Promise('C') ).then( () => testFunc_Promise('D') ).then( () => testFunc_Promise('E') ).then( () => testFunc_Promise('F') ); } // main_PromiseThenThenArrow(); // 実行結果 // testFunc_Promise name:A interval:3 // testFunc_Promise name:B interval:8 // testFunc_Promise name:C interval:4 // testFunc_Promise name:D interval:6 // testFunc_Promise name:E interval:2 // testFunc_Promise name:F interval:8 // -------------------- const main_PromiseThenThenMiss = () => { testFunc_Promise('A').then( () => { testFunc_Promise('B') } ).then( () => testFunc_Promise('C') ).then( () => testFunc_Promise('D') ).then( () => testFunc_Promise('E') ).then( () => testFunc_Promise('F') ); } main_PromiseThenThenMiss(); // 実行結果 // testFunc_Promise name:A interval:10 // testFunc_Promise name:C interval:3 // testFunc_Promise name:B interval:4 // testFunc_Promise name:D interval:6 // testFunc_Promise name:E interval:6 // testFunc_Promise name:F interval:8
- 投稿日:2020-08-23T14:26:27+09:00
redux-observable Epicがどう動くかを理解する
何についての記事か
ざっくりまとめるとredux-observableについて公式Docを読むだけではわからない下記の疑問を解決する記事
- Epicに引数として渡されるaction\$,state$とはなんなのか どこから来るのか?
- ActionがDispatchされてからどのようにEpicの処理が実行されるのか?
- Epicが返すpiped ObservableのObserverはどこで定義され、どんなロジックが動いているのか?
前談 : Docを読んで使い方を理解する
RxJSベースでReduxの非同期処理を記述できるredux-observable
公式Docを読んでみると、以下のようなサンプルがあります。import { ajax } from 'rxjs/ajax'; // action creators const fetchUser = username => ({ type: FETCH_USER, payload: username }); const fetchUserFulfilled = payload => ({ type: FETCH_USER_FULFILLED, payload }); /// epic const fetchUserEpic = action$ => action$.pipe( ofType(FETCH_USER), mergeMap(action => ajax.getJSON(`https://api.github.com/users/${action.payload}`).pipe( map(response => fetchUserFulfilled(response)) ) ) );上記のexampleは要約すると以下
- FETCH_USERアクションがdispatchされた時に処理を行う
- ajaxでapiにgetリクエストを投げる
- apiからの返却値をpayloadとしてFETCH_USER_FULFILLEDアクションをdispatchする
RxJSのoperatorの使い方がわかっていれば真似して実装することは難しくありません。
ドキュメントを読むことでredux-observableの基本的な使い方は理解できるし、実装に入ることができます。ドキュメントを読んで理解できたこと
- redux-observableで非同期処理を行う = Epicを作成する
- action\$.pipeにoperatorを組み合わせて値の加工、APIへのリクエストを行う
- epic(action\$, state\$).subscribe(store.dispatch)となるらしいので、epicはActionを値として出力するObservableが返せばいい
ドキュメントの文量は多くなく、exampleを見ればapi fetchとその結果を含んだAcitionをdispatchする書き方はすぐにわかります。
とりあえず真似して実装を進めることはできるでしょう。ドキュメントを読んでもわからなかったこと
- Epicに引数として渡されるaction\$,state$とはなんなのか どこから来るのか?
- ActionがDispatchされてからどのようにEpicの処理が実行されるのか?
- Epicが返すpiped ObservableのObserverはどこで定義され、どんなロジックが動いているのか?
これらは知る必要がないのだから、ドキュメントに書かれないのは当然。
とはいえ、せっかくObservableに触れるのだからReactive Programmingであることを意識しながら実装を進めた方が学びが多いでしょう。
Observableの流れを理解した上で非同期処理が実装できるようになることを目標に掘り下げていきます。Epicについて
掘り下げるにあたって、Epicについてもう少しだけ確認しておきましょう。
Epicは以下のような形式の関数。redux-observableを使用して非同期処理を書くということはEpicを作成するということになります。/// epic const fetchUserEpic = (action$, state$, dependancies) => action$.pipe( ofType(TARGET_ACTION_TYPE), // some operators );第一引数のactions\$はObservable。何らかのActionがdispatchされると、そのActionが値としてストリームを流れます。
actions\$のpipeメソッドに処理を登録していくことで、トリガーとなるAction(この例ではTARGET_ACTION_TYPE)がdispatchされたあとのロジックを作成することができます。第二引数のstate\$もobservable。こちらはredux-observableによって拡張されたクラスで、valueというプロパティを持っています。
処理をに使うというよりはstoreを参照するために利用されるもので、Epicの中でstateの値を参照したいときは\$state.valueを参照すればいいわけです。第三引数のdependanciesはredux-observableの全体の動作を把握する上では一旦重要でないのでこちらのドキュメントを参照してください
【公式】Injecting Dependencies Into Epicsドキュメントのexampleだけ見てもaction\$, state$が何処から来て何処へいくものなのかがよくわからず戸惑いがちだと思います。
Observarも登場しないので不慣れな人にとってはObservableパターンであることもわかりにくいかもしれません。
その辺りについて理解するために下記でEpicMiddlewareについて解説しています。ちなみに、公式ドキュメント曰くaction\$についている\$は便宜上ついている識別子であって特に深い意味はないらしいのでそういう名前だと割り切りましょう。
EpicMiddlewareについて
redux-observableを利用する場合はepicMiddlewareを使用することになります。
下記のように適用します。import { createEpicMiddleware } from 'redux-observable'; import { reducer } from '../path/to/reducer'; import { rootEpic } form '../path/to/rootEpic'; const epicMiddleware = createEpicMiddleware(); const store = createStore(reducer, applyMiddleware(epicMiddleware)); epicMiddleware.run(rootEpic);EpicMiddlewareの動作やEpicとの関係を図で表してみました
私たちが作成するEpicはEpicMiddlewareの処理をきっかけに動作します。
Epicの引数となるaction\$, state\$はcreateEpicMiddleware()実行時に作成されます。
つまり、createEpicMiddleware.tsを読み解くことができれば、redux-observableの全体動作を掴むことができます。createEpicMiddleware.tsを読み解く
ActionをDispatchされた時の動作
EpicMiddlewareのコードの内、Actionがdispatchされたときに処理を開始するトリガーの部分から見ていきます。非常にシンプルです。
上図の中央のEpicMiddlewareの部分です。// createEpicMiddleware.ts Line 86 return next => { return action => { const result = next(action); stateSubject$.next(store.getState()); actionSubject$.next(action); return result; }; };処理1. next(action)
なんらかActionがDispatchされると、まずは後続のmiddlewareの処理とreducerの処理を先に完了させます。
Epicの処理が走るのはreducerによってstoreが更新された後になります。処理2. stateSubject\$.next(store.getState())
storeからstateを取得し、stateSubject\$.next()を実行してサブジェクトにstateを値として注入します。
stateSubject\$のObserverによってstate\$.valueが注入された値に置き換わります。
つまり、なんらかのActionがdispatchされた度にstate\$.valueは最新化されます。処理3. actionSubject$.next(action)
actionをactionSubject\$に注入しています。
あとで詳しく書きますが、action\$はactionSubject\$をソースとしたObservableなのでactionSubject\$に値が注入されるとaction\$のストリーム処理が実行されることになります。
つまり、この行がEpicを動作させるためのトリガーになっています。stateSubject$とactionSubject$の生成
なんらかのActionがdispatchされた時にstateSubject\$とactionSubject\$に値が注入されることはわかりました。
この2つのSubjectがどのように生成され、どう使われているかを見ていきます。// createEpicMiddleware.ts Line 53 const actionSubject$ = new Subject<T>(); const stateSubject$ = new Subject<S>(); const action$ = actionSubject$ .asObservable() .pipe(observeOn(uniqueQueueScheduler)); const state$ = new StateObservable( stateSubject$.pipe(observeOn(uniqueQueueScheduler)), store.getState() );actionSubject\$, stateSubject\$はRxJSの純粋なSubjectクラスのインスタンスです。
state\$はStateObservableクラスのインスタンスです。このクラスはObservableを継承したものでvalueプロパティが追加されています。
constractor第一引数のstateSubject\$を値の入り口としてvalueを更新します。 例: stateSubject\$.next(value)
StateObservable自身はObserverを持たず、valueプロパティの更新以外は行いません。action\$はactionSubject\$をObservableに変換したインスタンスです。
ここで作成されたaction\$とstate\$がEpicの引数として渡されます。
次は、Epicが呼び出される部分のコードを読んでみましょう。Epicの呼び出し
上の概略図でいうと左下あたりのEpicとそのObservableとObserverのあたりです。
const epic$ = new Subject<Epic<T, O, S, D>>(); // ... // createEpicMiddleware.ts Line 63 const result$ = epic$.pipe( map(epic => { const output$ = epic(action$, state$, options.dependencies!); if (!output$) { throw new TypeError( `Your root Epic "${epic.name || '<anonymous>'}" does not return a stream. Double check you\'re not missing a return statement!` ); } return output$; }), mergeMap(output$ => from(output$).pipe( subscribeOn(uniqueQueueScheduler), observeOn(uniqueQueueScheduler) ) ) ); result$.subscribe(store.dispatch);epic\$はepicが注入されることを期待しているSubjectです。epicMiddleware.run(rootEpic)を動かした時にrootEpicを受け取る部分です。
epic\$.pipe()は2つのオペレーターを含んでいます。
1つ目のmapはシンプルにepicを実行して返り値を返しています。返り値が不正の場合はエラーを出力します。
2つ目のmergeMapでhigh order Observableとしてepicの返却値であるoutput$がmergeされています。以上からresult\$はepicの返り値であるoutput\$にSchedulerが追加されたObservableと言えます。
最後にresult\$のObservableとしてstore.dispatchを登録しています。
私たちがoperatorを追記して作成したEpicが出力する値(Action)がそのままstore.dispatchに渡されることがわかります。色々とwrapされて名前が変わっているのがわかりづらいですが、result\$のソースはactionSubject\$です。
「ActionをDispatchされたときの動作」のところで説明したactionSubject\$.next(action)がトリガーとなり、私たちが作成したEpicが返すObservableが動いて別のActionが出力され、Observerによってdispatchされていることがわかります。epicMiddleware.run()
// createEpicMiddleware.ts Line 103 epicMiddleware.run = rootEpic => { if (process.env.NODE_ENV !== 'production' && !store) { warn( 'epicMiddleware.run(rootEpic) called before the middleware has been setup by redux. Provide the epicMiddleware instance to createStore() first.' ); } epic$.next(rootEpic); };最後にstoreにmiddlewareを登録した後に実行するepicMiddleware.run()について
これは先ほどepicをwrapしていたepic\$にepicを渡す役割を持っています。最初の疑問への回答
冒頭、公式ドキュメントを読んだけどわからなかった疑問を挙げました。
EpicMiddlewareについて理解した今なら回答できるはずなので、答えを記して終わろうと思います。
Epicに渡されるaction$,state$とはなんなのか どこから来るのか?
→ createEpicMiddleware実行時に生成されるSubjectをソースとしたObservable
ActionがDispatchされてからどのようにEpicの処理が実行されるのか?
→ なんらかのActionがdispatchされるとEpicMiddlewareが$actionSubjectにActionを渡す それをトリガーにEpicの処理が動作する
Epicが返すpiped ObservableのObserverは何処で定義され、何をしているのか?
→ createEpicMiddleware実行時にEpicの返り値に参照を持つObservableの.subscribe()メソッドが起動され、store.dispatchがObserverのnextとして登録される。
以上。誤り、改善ポイントなどあればコメントいただければ幸いです。
- 投稿日:2020-08-23T14:04:11+09:00
【JavaScript】型を意識してないと、余計な時間を使うよって話
結論:.val()で取得した値を変数に代入した数値同士を足し算する時は文字列結合されます
やりたい事
- テキストボックスAに任意の数値を入力する
- テキストボックスBにはDBから
MAX(id)のデータを取得している- テキストボックスAとテキストボックスBの値を足してテキストボックスCに出力する
参考
足し算でうまくいかないのはなぜ?
http://www.dicre.com/ols/jvs/body29.html
parseInt
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseIntHTML
<table> <tr> <th>テキストボックスA(ここに任意の数字を入力)</th> <td><input type="number" id="inputNumber"></td> </tr> <tr> <th>テキストボックスB(ここにDBからMAX(id)のデータを表示)</th> <td><input type="number" id="getId" readonly="true"></td> </tr> <tr> <th>テキストボックスC(ここに計算結果を出力)</th> <td><input type="number" id="setValue" readonly="true"></td> </tr> </table>JS
イベントハンドラはkeyupとしてます
$(document).ready(function() { $("#inputNumber").keyup(function() { var getInputNumber = $("inputNumber").val(); var getIdNumber = $("getId").val(); $("#setValue").val(getInputNumber + getIdNumber); }); });計算結果
var getInputNumber = 10 var getIdNumber = 20 getinputNumber + getIdnumber →1020!!??
文字列結合になっている...掛け算・割り算をした時には問題なく正しい計算結果を返してくれていたのに、足し算はうまくいきません文字列には掛け算・割り算は存在しないので、暗黙の型変換が行われ、文字列を数値に変換して掛け算・割り算をしてくれますが、足し算の場合は文字列結合が当てはまってしまいます。(ご指摘頂きました。val()でテキストボックスから値を取得する場合は、基本的に文字列です。なので文字列+文字列の結果は文字列ですね…勉強になりました!)
var hoge = "私は" var fuga = "おにぎりを食べたいです" hoge + fuga →"私はおにぎりを食べたいです"この結果と同じく、先ほどの10 + 20 は文字列結合されて1020と返ってきます
parseInt関数を使いましょう
$(document).ready(function() { $("#inputNumber").keyup(function() { var getInputNumber = $("inputNumber").val(); var getIdNumber = $("getId").val(); $("#setValue").val(parseInt(getInputNumber) + parseInt(getIdNumber)); }); });parseInt関数は文字列の引数を解析して、整数と解釈して値を返してくれます
var getInputNumber = 10 →文字列"10" var getIdNumber = 20 →文字列"20" parseInt(getinputNumber) + parseInt(getIdnumber) →引数を整数"10" + 整数"20"と解析して値を返してくれる →30これで求めていた"30"という結果を得る事ができました
まとめ
動的型付け言語(rubyやphpなど)や暗黙の型変換のおかげ(??)で、あまり型を意識せずともプログラム側がよしなにやってくれます。単純に足し算をしただけの簡単な処理を書くだけなのに、型の意識が薄く余計な時間を使ってしまったので、型を意識したプログラムを書けるようにならなければいけませんね
おわり
- 投稿日:2020-08-23T13:56:21+09:00
【React】【textarea】改行のみ、文字未入力の際に送信ボタンを無効化する
都内スタートアップでフロントエンドエンジニアとしてReactを書いております。
最近業務でチャット機能を実装する際、タイトルどおりの実装が必要だったのでメモ程度に残していきます。全体イメージ
import React, {useState} from 'react'; const MessageForm = () => { const [message, setMessage] = useState(''); const isExistTextInInput = !!message.match(/[^\n]/) const sendMessage = () => { if(!isExistTextInInput) return //inputの値を送信!! } return ( <div> <textarea value={message} onChange={e => setMessage(e.target.velue)} /> <button onClick={() => isExistTextInInput && sendMessage} className={isExistTextInInput ? 'btn' : 'btn--disable'} > 送信 </button> </div> ); };解説
きもは下記変数です
const isExistTextInInput = !!message.match(/[^\n]/)
String.prototype.match()正規表現全体に一致したすべての結果を配列で返します
何もないとnullになります
!!でboolに型変換配列ならfrue, nullならfalseが返ります
条件である
[^\n]
^は、〜以外という正規表現\nは改行の正規表現なので下記条件分岐になります。
改行以外の文字列がある => 配列が返る
文字列がない、改行しかない => nullが返るまとめ
あとは
isExistTextInInputを使ってボタンのメゾット発火を無効にしたり、クラスを付け替えるだけです
めちゃめちゃ簡単なのでお試しあれキーボード操作系の
エンターシフトで送信や、","でタグを追加だったりも実装したので後にまとめようかなと思います!
- 投稿日:2020-08-23T13:48:08+09:00
【React】デフォルト値もundefinedチェックもいらないcreateContext【Typescript】
Introduction
Typescriptによる型定義とContextによるState管理で、ReactのDX(Developer Experience)は劇的に進化しました。
しかし、素晴らしい型定義によって、謎に苦しめられることもあります。
Problem
createContextにはデフォルト値を渡す必要がありますが、往々にしてそのデフォルト値はundefinedです。const AuthContext = React.createContext<authContextType | undefined>(undefined);これの何が問題なのでしょうか?
それはContextを使用する際に致命的になります。// どこかでuseContextして作られたuseAuth関数 const Auth = useAuth()!;
createContextのデフォルト値としてundefinedを指定したことで、Contextを使用する際にその値がundefinedでないかを”全ての場所で”逐一確認する必要があります。根本的に、
undefinedはアプリケーションにとって何の意味もなさない値です。
それを、わざわざ確認しなければいけないということは、バグやエラーの温床になります。Solution
デフォルト値を
undefinedとせず、未定義チェックを行えるcretaeContextのwrapperを作成して解決します。function createCtx<ContextType>() { const ctx = React.createContext<ContextType | undefined>(undefined); function useCtx() { const c = React.useContext(ctx); if (!c) throw new Error("useCtx must be inside a Provider with a value"); return c; } return [useCtx, ctx.Provider] as const; }今回の問題は、デフォルト値
undefinedのContextに対して、useContextをしてしまうとでundefinedがuseContextに紛れ込んでしまうことでした。そこで、wrapper関数に未定義チェック関数を定義し、
useContextがundefinedである場合はエラーをthrowします。これで、wrapper関数
createCtxで定義されたuseCtxは、<ContextType>で渡されるジェネリック型を返します。
無事、useContextからundefinedを駆逐しました。Example
ユーザー管理、ログイン、ログアウトなどを管理するContextのExampleを作ってみました。
type User = { id: string; name: string; }; type authContextType = { user: User | null; signIn: () => void; signUp: () => void; signOut: () => void; }; function createCtx<ContextType>() { const ctx = React.createContext<ContextType | undefined>(undefined); function useCtx() { const c = React.useContext(ctx); if (!c) throw new Error("useCtx must be inside a Provider with a value"); return c; } return [useCtx, ctx.Provider] as const; } const [useAuth, SetAuthProvider] = createCtx<authContextType>(); const AuthProvider: React.FC = (props) => { const auth = useAuthCtx(); return <SetAuthProvider value={auth}>{props.children}</SetAuthProvider>; }; const useAuthCtx = (): authContextType => { const [user, setUser] = React.useState<User | null>(null); const signIn = () => { // Some sign in action }; const signUp = () => { // Some sign up action }; const signOut = () => { // Some sign out action }; return { user, signIn, signUp, signOut }; }; export const App = () => { const auth = useAuth(); return ( <AuthProvider> <button onClick={() => {auth.signIn()}}>ログイン</button> <button onClick={() => {auth.signUp()}}>サインアップ</button> </AuthProvider> ); };Sample
【Qiita記事準備中】 React.createContextで管理するFirebase Authentication
Happy Hacking!!?
苦情受付中...✍️
- 投稿日:2020-08-23T13:04:26+09:00
JavaScriptを使った10秒ちょうどで止めるやつを作った
JavaScriptを使った10秒ちょうどで止めるやつを作った
プログラミング初心者なので、とりあえずフロントエンドからやろうということで、本を参考にしながら何か作ってみました。
最初はネットにある情報だけでなんとかしようとしたけど全然ダメで、やっぱり本は買うべきだなーと感じました。参考文献
これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほん
まだ最後らへんはやってないですけど、めちゃくちゃ良書だと感じました。他の本をやっていないため比較することはできませんが、気になっていたBootstrapやjQuery、Vue.jsまで入っているのでお得感あります。
開発環境
- Windows 10 Home
- Visual Studio Code 1.44.2
- Google Chrome
コード
HTML
index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <title>10秒ピッタリで止めるやつ</title> <link type="text/css" rel="stylesheet" href="style.css"> <script type="text/javascript" src="10seconds.js"></script> </head> <body> <div class="container"> <p id="timer">00:00</p> <button id="button" class="start" onclick="clicked(this)">START</button> <p id="comment"></p> </div> </body> </html>HTMLに関しては、どういう機能があるかとかはだいたい理解できた気がします。ただ、一般的にどう使うかみたいなのはまだ全然分からないので、どんどん作っていくしかないかなと思います。
CSS
style.css.container{ text-align: center; max-width: 600px; margin: 50px auto; } #timer{ background-color: black; color: rgb(16, 245, 46); font-size: 128px; margin: 0 auto; width: 600px; } #button{ margin-top: 30px; font-size: 64px; width: 600px; color: white; text-align: center; border: solid white; } #comment{ font-size: 64px; color: black; text-align: center; } .start{ background-color: rgba(0, 119, 255, 0.651); } .stop{ background-color: rgba(255, 0, 0, 0.87); } .reset{ background-color: rgba(0, 255, 21, 0.87); }これも一応ルールとかについては理解できましたが、まだまだ知らないことが多すぎるので、これは知識を増やすことが必要かなって感じですね。
JavaScript
10seconds.js//グローバル変数の宣言 var start; var display; var timer_id; var milli; //keta関数 //桁合わせをする関数 function keta(value) { //値が10より小さい場合 if(value < 10) { //桁合わせをするために0を追加 value = '0' + value; } return value; } //check関数 //タイマー表示のための関数 function check() { //Dateオブジェクトの生成 var count = new Date(); //1970年1月1日からの経過時間をミり秒単位で取得 milli = count.getTime(); //時間差を計算 milli -= start; //1/1000を整数で表示するため、10で割り、1/100秒単位をmilliに入れる milli = Math.floor(milli/10); //milliを100で割り、1秒単位を計算し、secondに入れる var second = Math.floor(milli/100); //milliが0~99以外の値を取らないようにする //表示する文字列を作るdisplay display = keta(second) + ':' + keta(milli - second * 100); //タイマーに表示する document.getElementById('timer').innerHTML = display; } //clicked関数 //クリックされたときに実行される function clicked(ele) { //ボタンの文字がSTARTのとき if(ele.innerHTML === 'START') { //Dateオブジェクトの生成 var now = new Date(); //1970年1月1日からの経過時間をミり秒単位で取得 start = now.getTime(); //0.01(10/1000)秒ごとにcheck()関数を実行 timer_id = setInterval(check,10); //ボタンの文字をSTOPにする ele.innerHTML = 'STOP'; //classからstartを外す ele.classList.remove('start'); //classにstopを加える ele.classList.add('stop'); } //ボタンの文字をSTOPのとき else if(ele.innerHTML === 'STOP') { //タイマーを止める clearInterval(timer_id); document.getElementById('timer').innerHTML = display; //符号用の変数 var sign; //差を計算 var diff = milli - 1000; //符号を調べる if(diff > 0) sign = '+'; else sign = '-' //時間差を計算する document.getElementById('comment').innerHTML = sign + keta(Math.floor(Math.abs(diff)/100)) + ':' + keta(Math.floor(Math.abs(diff)%100)); //ボタンの文字をRESETにする ele.innerHTML = 'RESET'; //classからstopを外す ele.classList.remove('stop'); //classにresetを加える ele.classList.add('reset'); } else { //タイマーをリセット document.getElementById('timer').innerHTML = '00:00'; //時間差の表示を消す document.getElementById('comment').innerHTML = null; //ボタンの文字をSTARTにする ele.innerHTML = 'START'; //classからresetを外す ele.classList.remove('reset'); //classにstartを加える ele.classList.add('start'); } }一応C、C++についての基礎知識があったので、関数とかif文とかについてはすんなり理解できました。ただ、グローバル変数をかなり多く使ってしまったり、計算式が分かりづらかったりしたのはもう少し改善できたのかなって感じがします。
感想と反省
本に書いてあったのは普通のタイマーだけだったので、ボタンの切り替えなんかは自分で考えてやってみたので、もしかしたら変なことをしているのかもしれません。もっと他の人のコードを見て勉強しようと思います。
結構時間をかけてしまったので、もっとスピーディにやっていこうと思いました。
- 投稿日:2020-08-23T12:37:19+09:00
inputのrangeのデザインを変えたいので1から作成した
はじめに
皆様はrangeのつまみ部分のデザインを変えたいと思ったことはないでしょうか。
知らべてみると、::-webkit-slider-thumbで変更出来ますが、非標準です。しかもこれには擬似要素が付与出来ません。
困った時のstackoverflowで質問してもやはり無理とのこと...。じゃあ、作るか!
前提知識
rangeの見た目はブラウザによって違う
rangeの見た目はブラウザによって違います。
input type=range タグをカスタマイズするためにこれは2017年の記事ですが、例えばchromeではデザインが変更されていたりします。
Chrome のフォーム コントロールとフォーカスのアップデート
このため、今後もずっと同じ見た目とは限りません。素のままでは変更する量が多い
input type=range タグをカスタマイズするために
この記事を見てもらえればわかりますが、ブラウザによって変更する擬似要素が違います。
つまり、全ブラウザで同じ見た目にする場合は全てリセットしなければなりません。その上、全要素を指定しなければなりません。本編
上記を踏まえ、作成していきます。
属性は、min,max,valueをつけます。step?知らんな(すみません実装出来ませんでした)See the Pen range by 暁の流星 (@nomber1910) on CodePen.
今回はChromeのrangeに似せて作成しました。個人的にほぼ似ていると思います。
良い点
- つまみが好きにデザイン出来る
- つまみ単体を一つの要素で作成しているので好きにデザインすることが出来ます。
- その他も好きにデザイン出来る
- その他も一つ一つを別の要素で作成しているので好きにデザインすることが出来ます。
- 挙動を自分で変えることが出来る
- 中の挙動は全てJSで作成しているので自分で挙動を変えることが出来ます。
悪い点・反省点
- ドラッグが出来てしまう
- 今回実装するにあたって、一つ一つをdivで作成したため、つまみをスライドする際にドラッグしてしまい、挙動がおかしくなってしまう時があります。
- stepが実装できなかった
- 段階を踏んでつまみを動かすのが難しかった。こればかりは実力不足。
- スマホ対応していない
- スマホ対応むず~い。
まとめ
HTMLのタグ作ってる人偉いね。
でも開発が止まってる以上自分で開拓しなければならないジレンマ。
次のバージョンで変更できるようになってるといいな。
- 投稿日:2020-08-23T11:38:26+09:00
JavaScript 入門 基礎 オブジェクトについての理解
最近の学び
自分は2019年の8月からプログラミングを学び始めて、現在が2020年8月でちょうど一年が経ちました。
まずProgateでHTML/CSSを学び、ご多分にもれずに挫折しその後もう一度頑張ろうという事で、Progateとドットインストールを行ったり来たりしながらHTML/CSSを学びました。
そしてそこで、通おうと決めたスクールが、Ruby , Ruby on railsを教えていたのでRubyを学び始めました。オブジェクト指向?
Rubyを学んでいく中で一番理解ができなかったのがオブジェクト指向でした。
if文やfor文や配列や連想配列等の文法についてはなんとなく理解はできたのですが、オブジェクトとは『設計図』や『Rubyでは全てをオブジェクトとして扱います』といわれても意味がわかりませんでした。スクールで一番の難関
スクールでのカリキュラムで一番の難関と生徒同士で話題になっているものがありました、それがJavaScriptでの非同期通信Ajaxを使ったメッセージ送信機能とインクリメンタルサーチと自動更新機能でした。(正しくはjQueryで)Ajax?非同期?インクリメンタル??
その時自分はこれが意味不明すぎてrailsもよく分からないし、まったく理解できずにメンターの人に助けられっぱなしのまま終了しました。
その時の経験から自分はjQueryで記述を減らしてもこんなに難しいのに、JavaScriptとか絶対無理と思いJavaScriptに強い苦手意識がありました。
しかしその時は、サーバーサイドとフロントエンドの違いも分からないレベルでどこにJsを書いたらrailsのアプリで動くのか分からないレベルで学んでいたので、今ならもっと吸収できるのに!!と切実に感じています。。色々遠回りしながらも学び続けて1年
その後も1年間ほぼ毎日学習を継続し、サーバーサイドを学び続けたわけでもなく、途中でフロントエンド、コーダーとして働く事を決めフロントのコーディングを中心に学習してきたのですが、最近になってJavaScriptを本気でやってみようと決め、今までjQueryで動きをつける程度しか書いた事がなかったのですが、JavaScriptについて色々学んでクイズアプリ等を作っていろいろな記事や動画でアウトプットとインプットをして学んでいると、いきなりオブジェクト指向ってこういう事?!みたいに少し気付きがあり感動したのでまとめました。
まとめ
オブジェクト(データと機能をまとめたもの)にはプロパティ(データに相当)とメソッド(機能に相当)がある
window(ブラウザ)自体もオブジェクトである、windowは省略して記述できる
今まで知らずに当たり前のように使っていた、console.log("")やalert("")も
本来は、window.console.logであるとか、window.alertということ
本来ならwindow.document.getElementById('○○')であるとか
windowの中のプロパティのdocumentの中のID○○を取得するとか
windowというオブジェクトにはfecthというメソッドが存在する=>外部とデータのやりとりができるといった事が理解できました。
今まではwindowであったり、documentといった記述をおまいじないの様に書いていたので、
データの中の何のプロパティをDOMで操作するのかといった事の理解が深まりました。次に学ぶ事
・高階関数
・匿名関数
・コールバック関数
・WebAPIを叩く async await構文を学ぶ
- 投稿日:2020-08-23T11:38:26+09:00
JavaScript 基礎 オブジェクトについて学んだ事
振り返り
2019年の8月24日からプログラミングスクールに通って、ちょうど一年ぐらいが経ちました。
まずProgateでHTML/CSSを学び、ご多分にもれずに挫折しその後もう一度頑張ろうという事で、Progateとドットインストールを行ったり来たりしながらHTML/CSSを学びました。
そしてRuby , Ruby on railsを学び始めました。オブジェクト指向?
Rubyを学んでいく中で一番理解ができなかったのがオブジェクト指向でした。
if文やfor文や配列や連想配列等の文法についてはなんとなく理解はできたのですが、オブジェクトとは『設計図』や『Rubyでは全てをオブジェクトとして扱います』といわれても意味がわかりませんでした。JavaScript苦手
スクールでのカリキュラムで一番の難関と生徒同士で話題になっているものがありました、それがJavaScriptでの非同期通信Ajaxを使ったメッセージ送信機能とインクリメンタルサーチと自動更新機能でした。(正しくはjQueryで)Ajax?非同期?インクリメンタル??
その時自分はこれが意味不明すぎてrailsもよく分からないし、まったく理解できずにメンターの人に助けられっぱなしのまま終了しました。
その時の経験から自分はjQueryで記述を減らしてもこんなに難しいのに、JavaScriptとか絶対無理と思いJavaScriptに強い苦手意識がありました。
しかしその時は、サーバーサイドとフロントエンドの違いも分からないレベルでどこにJsを書いたらrailsのアプリで動くのか分からないレベルで学んでいたので、今ならもっと吸収できるのに!!と切実に感じています。。学び続けて1年
その後も1年間ほぼ毎日学習を継続し、サーバーサイドを学び続けたわけでもなく、途中でフロントエンド、コーダーとしてまず働く事を決めフロントのコーディングを中心に学習してきたのですが、最近になってJavaScriptを本気でやってみようと決め、今までjQueryで動きをつける程度しか書いた事がなかったので、JavaScriptについて色々学んでクイズアプリ等を作っていろいろな記事や動画でアウトプットとインプットをして学んでいると、いきなりオブジェクト指向ってこういう事?!みたいに少し気付きがあり感動したのでまとめました。
学んだ事まとめ
オブジェクト(データと機能をまとめたもの)にはプロパティ(データに相当)とメソッド(機能に相当)がある
window(ブラウザ)自体もオブジェクトである、windowは省略して記述できる
今まで知らずに当たり前のように使っていた、console.log("")やalert("")も
本来は、window.console.logであるとか、window.alertということ
本来ならwindow.document.getElementById('○○')であるとか
windowの中のプロパティのdocumentの中のID○○を取得するとか
windowというオブジェクトにはfecthというメソッドが存在する=>外部とデータのやりとりができるといった事が理解できました。
今まではwindowであったり、documentといった記述をおまいじないの様に書いていたので、
データの中の何のプロパティをDOMで操作するのかといった事の理解が深まりました。次に学ぶ事
・高階関数
・匿名関数
・コールバック関数
・WebAPIを叩く async await構文を学ぶ
- 投稿日:2020-08-23T10:29:15+09:00
@firebase/testingをやめて@firebase/rules-unit-testingを使おう
2020年8月20日にFirebase SDKの7.19.0がリリースされました。このバージョンではTestingSDKに以下のアップデートが入りました。
@firebase/testingのいわば後継として、新たに@firebase/rules-unit-testingがリリースされました。名前が変更されて、何のためのパッケージなのかわかりやすくなりました。対応PRは、引用RTでmonoさんが教えてくださったこちらになります。https://t.co/SmfbOhJNTf が対応プルリクで、そこにこの変更に至った議論のリンクが載ってたけど中の人しかアクセスできなかった( ´・‿・`) https://t.co/KrKn1FrBJR
— mono (@_mono) August 22, 2020軽く目を通してみると、このリリースに至った経緯はGooglerしか見ることができませんでした。しかし、破壊的変更が発生するにも関わらずこのリリースを行ったことを考えると、今後はこの新しいTestingSDKを使っていくほうがよいでしょう。
違い
ReleaseNoteに記載されているとおりですが、以下の違いがあります。
- インターフェースは互換性がある
assertFails()の挙動が変わる
- いままではassertFailsの引数に渡したPromiseがrejectされればfailとしていたようだが、今回からFirestoreのrulesに弾かれたときに発生する
PERMISSION_DENIEDのときのみfailとするようになる。これにより、より正確なrulesのテストになる。initializeAdminApp()がfirebase-admin依存になる
- 今までは
firebase-adminを模倣したインスタンスを返していたが、新しいパッケージではfirebase-adminを使ってインスタンスを返すようになる対応
@firebase/rules-unit-testingをインストールします。すでに@firebase/testingを使っている場合は、不要になるのでアンインストールしておきましょう。$ npm uninstall @firebase/testing $ npm i -D @firebase/rules-unit-testingimport文を書き換えます。
- import * as firebase from '@firebase/testing' + import * as firebase from '@firebase/rules-unit-testing'書き換えが完了したら一度テストを実行してみるとよいでしょう。テストの書き方によってはいくつかFAILしているかもしれません。それは、
setメソッドでTimestampやFieldValueがinvalid objectとかinvalid dataというエラーの場合は下記が原因です。client用Firestoreとadmin用Firestoreは別物
下記のようにする必要があります。
import * as firebase from '@firebase/rules-unit-testing' import * as admin from 'firebase-admin' const projectId = 'sample' const databaseName = 'test' const clientFirestore = firebase.initializeTestApp({ projectId, databaseName }).firestore() const adminFirestore = firebase.initializeAdminApp({ projectId, databaseName }).firestore() const clientUserRef = clientFirestore.collection('users').doc() const adminUserRef = adminFirestore.collection('users').doc() // OK: Client用のFirestoreには@firebase/rules-unit-testingから生成したFieldValueを渡さなければならない clientUserRef.set({ createdAt: firebase.firestore.FieldValue.serverTimestamp() }) // NG: Client用のFirestoreにfirebase-adminから生成したFieldValueを渡すとエラーになる clientUserRef.set({ createdAt: admin.firestore.FieldValue.serverTimestamp() }) // OK: Admin用のFirestoreにはfirebase-adminから生成したFieldValueを渡さなければならない adminUserRef.set({ createdAt: admin.firestore.FieldValue.serverTimestamp() }) // NG: Admin用のFirestoreに@firebase/rules-unit-testingから生成したFieldValueを渡すとエラーになる adminUserRef.set({ createdAt: firebase.firestore.FieldValue.serverTimestamp() })ようするにFirestoreに渡す値はパッケージが一致している必要があるということです。これが一致していないとエラーになります。実際、私が担当しているプロダクトのTestingSDKを差し替えるとこれに起因するエラーがいくつか発生していました。(いままでは、逆に、admin用のFirestoreにfirebase-adminから生成したTimestampを渡すとエラーになっていたと思う)
おわりに
何か間違っている点などありましたらコメントいただけると幸いです。また、Firebaseに関する発信をTwitterとYoutubeでおこなっているので、よければ見てください。
- 投稿日:2020-08-23T08:09:50+09:00
簡易CMSで無料ブログを公開、カスタム レイアウトを複数追加 #Vue #Vue-CLI #javascript
概要
事例的な内容となります。
CMSのアップデート内容で、
レイアウトを追加しました。・デモサイトは、GithubPagesに設置して例になります。
・投稿データ等の、編集機能は前回と同じで。MD書式対応です
環境
Vue CLI
vue: 2.6.11
vue-router
前の関連のページ
前の CMS表示の内容
https://note.com/knaka0209/n/nc10d352550ed
画面 Top
・type2, グリッドレイアウト風の
投稿データ表示となります。■ 参考の、デモのページ
https://kuc-arc-f.github.io/cms-sample-type2
■ 参考のコード
https://github.com/kuc-arc-f/vue_spa3cms3_type2
■ 参考の、デモのページ 、type3
https://kuc-arc-f.github.io/cms-sample-type3
■ 参考のコード , type3
https://github.com/kuc-arc-f/vue_spa3cms3_type3
・type4
初版と、似ていますが、サイドに。twitterタイムラインを埋込可能な形です。
■ 参考の、デモのページ 、type4
https://kuc-arc-f.github.io/cms-sample-type4
■ 参考のコード 、type4
https://github.com/kuc-arc-f/vue_spa3cms3_type4
■ 補足
・初版レイアウトの、デモはこちら
https://kuc-arc-f.github.io/cms-sample
- 投稿日:2020-08-23T04:30:27+09:00
生のNode.jsでプロジェクト作成時にやること
当然ではありますが、生のNode.js(特にWebアプリ)でプロジェクト作成時にやることが多く、HTTP通信に関する勉強にもなったのでメモを残しておきます。
Node.jsに関してはほぼ初心者なので、不足や誤りがあるかもしれません。発見した場合はコメントなどでご報告いただけますと幸いです。プロジェクトの初期化
とりあえず初期化。
いろいろ聞かれるので、それぞれのプロジェクトに合った選択をしていきます。$ npm init
- package name: (フォルダ名) プロジェクトの名前を定義します。特に変更がなければそのままReturnまたはEnterでOK。
- version: (1.0.0) バージョンを定義します。これも1.0.0のままでよければそのままReturnまたはEnterでOK。
- description: プロジェクトの概要を定義します。これも空白のままでよければそのままReturnまたはEnterでOK。
- entry point: (index.js) アプリケーションを起動するためのファイルを指定します。index.jsやmain.jsが多そう?これもindex.jsのままでよければそのままReturnまたはEnterでOK。
- test command: テストコマンドの指定をします。これも空白のままでよければそのままReturnまたはEnterでOK。
- git repository: Gitのリポジトリを指定します。これも空白のままでよければそのままReturnまたはEnterでOK。
- keywords: npmに公開した時のキーワードを設定します。今回はWebアプリを作ることを想定しているのでそのままReturnまたはEnterでOK。
- author: 製作者の名前を設定します。これもnpmに公開した時に使われるようなので、そのままReturnまたはEnterでOK。
- license: (ISC) npm に公開された時のライセンスを記述します。これもnpmに公開した時に使われるようなので、そのままReturnまたはEnterでOK。
-yを末尾につけることで、すべてデフォルトのまま初期化することができます。
http-status-codesをインストールする
$ npm install http-status-codes --save #--saveはNode.js 5.0.0以降は自動で付与されるのでいらないサーバーがリクエストの受信に成功したことを表す200や、Not foundを表す404などを返します。
リクエストとレスポンスに最低限必要なコードを書く
ポート番号の設定
index.jsconst port = 3000; //今回は3000番ポートを使用。httpモジュールのロード
index.jsconst http = require('http');http-status-codesモジュールのロード
index.jsconst http-status-codes = require('http-status-codes');サーバーを作成する
index.jsapp = http.createServer((req, res) => { res.writeHead(httpStatus.OK, { 'Content-Type': 'text/html' }); res.write('<h1>Hello, World!</h1>'); res.end(); });httpStatus.OKには200が入っています。
これをres.writeHeadの引数にとることで、リクエストが成功したことを表します。
その後、res.write()でボディを記述し、res.end()でレスポンスを閉じることで、クライアントにレスポンスを送信します。ポートの監視
このコードの初めに記述した3000番ポートを監視します。
index.jsapp.listen(port);これでlocalhost:3000にアクセスすることができるようになりました。
実際にブラウザからアクセスしてみると、下の写真のようになっています。
まとめ
これで、サーバーを立てることができるようになりました。
実際にExpressなどのフレームワークなどを一切使わずにNode.jsをサーバーサイドとして使用する機会はあまり多くはないと思いますが、通信の仕組みをやんわりと理解することにも役立ちそうな気がします。








