- 投稿日:2021-10-26T22:28:17+09:00
obniz feat.BAIKIN-MAN!
パパの目論見 うちの次女はアンパンマンが大好きでバイキンマンが大嫌いな典型的な2歳児なのですが、 ガチャポンで出てくるのは、決まってバイキンマンだったりします 今回の企画はバイキンマンを使ったおもちゃを作り、 娘に好きになってもらおうバイキンマンを克服してもらおうというものです。 逃げる者を追いたくなるのは人間の性でしょうから、近づいたら逃げるバイキンマンを作ります。 名付けて、「BYE-BAIKIN-MAN!!」 obnizを手に入れたので、いざトライ! 試作品 超振動距離センサとサーボモーターを組み合わせて、動力にしたいと考えました。 この超振動を使えば、地面を叩いてやつらは動くはずである!これは期待できそうだ! 完成品「BYE-BAIKIN-MAN?」 小刻みに震えるバイキンマンが出来上がった。。。笑 ガチャポン排出品のサイズ感を考えてなかった。。。 番外編 その後タイヤが大きいと、かろうじて前進できることを確認。 ただし、バイキンマンではないので却下! こっから先は力学?な気がしたので、追い求めるのをやめました。笑 あと、もともとは、動く前にランプが点滅する無駄仕様を取り入れていたのですが、 施行繰り返し過ぎたせいか破壊してしまい、焦げ臭かったのでやめました。 材料 ●obniz Board 1Y ●マイクロサーボ 9G SG90 ●超音波距離センサモジュール HC-SR04 ソースコード const Obniz = require('obniz'); const obniz = new Obniz('****-****'); // Obniz_IDに自分のIDを入れます obniz.onconnect = async function () { // 超音波測距センサを利用する const servo = obniz.wired('ServoMotor', { gnd: 0, vcc: 1, signal: 2 }); // サーボモータを利用 const hcsr04 = obniz.wired('HC-SR04', { gnd: 11, echo: 10, trigger: 9, vcc: 8 }); // RGB LEDを利用 ➡不使用 //const rgbled = obniz.wired('WS2811', { gnd: 4, vcc: 5, din: 6 }); // ディスプレイ obniz.display.clear(); // クリア obniz.display.print('Ready'); // setIntervalで一定間隔で処理 setInterval(async function () { // 距離を取得 let distance = await hcsr04.measureWait(); // そのままだと小数点以下の桁数がやたら多いので整数に丸めてもよい //distance = Math.floor(distance); // 距離(mm)をターミナルに表示 console.log(distance + ' mm'); // obnizディスプレイに表示 // 一度消してから距離+mmの単位を表示 obniz.display.clear(); obniz.display.print(distance + ' mm'); // 距離がある程度未満かどうかの判定 if (distance < 100) { // XXmm = Xcm 以下の場合 // obnizディスプレイに近接していることを表示 obniz.display.clear(); obniz.display.print('GO!BAIKIN-MAN!'); //rgbled.rgb(255, 0, 0); // カウンターで回転回数を制御。180度と0度を繰り返す。 let cnt = 0; var angle = 0; let timerId = setInterval(async function(){ cnt++ if(cnt===5){ clearInterval(timerId); } else { servo.angle(angle); if (angle == 0) { angle = 180; } else { angle = 0; } } //rgbled.rgb(0, 0, 0); }, 1000); } }, 1000); // 1000ミリ秒 = 1秒おきに実行 } 実証実験 せっかくなのでこどもに見せてみました。 (妻のNGが出たので画像/動画はナシです。すみません。) どうやら、小刻みに震えるバイキンマンでも、見慣れないおもちゃは面白いようです。 分解後、もっかい作ってと言われたので、それなりに面白かったのでしょう。 丁重にお断りしました 次回作るときはちゃんと前進するバイキンマンを作ってあげたいものです
- 投稿日:2021-10-26T22:19:17+09:00
node.jsでHIITのTimerを作った
フィヨルドブートキャンプのプラクティスでnpmを自作しました。 せっかくなのでqiitaで公開させてもらおうと思ったので、勇気を出して書かせてもらってます。 「もっとこうした方がいいんじゃない?」などのご意見がありましたらコメントしてもらえると嬉しいです! どんなnpmを作ったのか 作ったnpmは、最近流行りのトレーニング手法であるHIIT(High Intensity Interval Training)のタイマーです。 話題の筋トレ「HIIT」とは? HIITとは、「High Intensity Interval Training(高強度インターバルトレーニング)」の略で、負荷の高い運動と小休憩を繰り返すトレーニング法のこと。限界まで体を追い込むことで、常に脂肪が燃焼しやすい状態をキープし、体脂肪減少と筋肉増量効果を得るものです。 実際に作成したnpmはこちらで確認できます↓ - npm:hiit_timer - GitHub:github.com/R-Tsukada/hiit-timer 実際どんな感じで動くのか ワークアウト時間の選択 インターバル時間の選択 1,2を何セット行うかを選択 作成したコード 最終的なコード const log = require('single-line-log').stdout const player = require('play-sound')(opts = {}) const { prompt } = require('enquirer') const emoji = require('node-emoji'); async function hiitTimer(){ const workoutTimer = await prompt( [ { type: 'select', name: 'workoutTime', message: 'select workout time', choices: ['10', '20', '30', '40', '50', '60'] }, { type: 'select', name: 'restTime', message: 'select rest time', choices: ['10', '20', '30', '40', '50', '60'] }, { type: 'select', name: 'set', message: 'select set number?', choices: ['1', '2', '3', '4', '5', '7', '8', '9', '10'] } ] ) const workout = workoutTimer.workoutTime const rest = workoutTimer.restTime const set = workoutTimer.set running(set, workout, rest) } async function running(setNumber, workout, rest){ await log('\x1b[32m10 seconds before Workout') await firstWorkout(10) for (let i = 0; i < setNumber; i++) { log(emoji.get('fist') + ` Set${i + 1} Workoout Start ` + emoji.get('fist')) await intervalTimer(workout) log((emoji.get('relaxed')) + ` Set${i + 1} Break ` + (emoji.get('relaxed'))) await intervalTimer(rest) } await log((emoji.get('congratulations')) + ' Workout Finish' + (emoji.get('exclamation')) + 'Good Job' + (emoji.get('exclamation')) + (emoji.get('congratulations'))) } function intervalTimer(selectWorkout) { return new Promise(resolve => { setTimeout(() => { const startEffect = player.play('start_effect.mp3') resolve() }, selectWorkout * 1000) } ) } function firstWorkout(second) { return new Promise(resolve => { setTimeout(() => { const startEffect = player.play('start_effect.mp3') resolve() }, second * 1000) }) } hiitTimer() 悩んだ点 今回色々悩んだことが、「ワークアウトとインターバルを設定したセット数を繰り返す」ことでした。 繰り返すということはsetIntervalを使えばいいのでは?と考えて、↓のような考え方をしていました。 console.log('First Workuout Start') const running = (function(){ console.log('First Workuout Start') let number = 1 setInterval(function() { if (number === 2) { console.log('break') } else if (number === 3) { console.log('Workuout Start') } number += 1 }, 1000) }) async function play(hiitNumber){ for (let i = 0; i < hiitNumber; i++) { running() }} play(1) このコードでも一応実装したい通りの動きになったのですが、、 First Workuout Start break Workuout Start play(3)のようにセット数を複数回繰り返すと、 First Workuout Start break break break Workuout Start Workuout Start Workuout Start break、Workuout Startが連続で処理されてしまってインターバルのタイマーになりませんでした。 非同期的に処理されてしまってるので、同期処理になるようにコードを変える必要性があるなと思いました。 修正した点 非同期処理が原因でインターバルタイマーの動きになってないので、同期処理になるようにコードを修正。 そもそもsetIntervalが非同期処理を前提にしたメソッドなので、setIntervalではなく、setTimeoutを繰り返し処理を使うことにしました。 intervalTimerというメソッドを作成して、workout(運動時間)、rest(休憩時間)の時間をそれぞれ引数で渡します。 まずはenquireを使ってworkout, rest, set(セット数)を決めます。 sync function hiitTimer(){ /* enquireで,workout、rest、setを選択 */ const workoutTimer = await prompt( [ { type: 'select', name: 'workoutTime', message: 'select workout time', choices: ['10', '20', '30', '40', '50', '60'] }, { type: 'select', name: 'restTime', message: 'select rest time', choices: ['10', '20', '30', '40', '50', '60'] }, { type: 'select', name: 'set', message: 'select set number?', choices: ['1', '2', '3', '4', '5', '7', '8', '9', '10'] } ] ) const workout = workoutTimer.workoutTime const rest = workoutTimer.restTime const set = workoutTimer.set running(set, workout, rest) } enquireで選択したworkout, restをsetTimeout に渡す。 function intervalTimer(selectWorkout) { return new Promise(resolve => { setTimeout(() => { const startEffect = player.play('start_effect.mp3') resolve() }, selectWorkout * 1000) } ) } async/await を使って同期処理で実行。 async function running(setNumber, workout, rest){ await log('\x1b[32m10 seconds before Workout') await firstWorkout(10) for (let i = 0; i < setNumber; i++) { log(emoji.get('fist') + ` Set${i + 1} Workoout Start ` + emoji.get('fist')) await intervalTimer(workout) log((emoji.get('relaxed')) + ` Set${i + 1} Break ` + (emoji.get('relaxed'))) await intervalTimer(rest) } await log((emoji.get('congratulations')) + ' Workout Finish' + (emoji.get('exclamation')) + 'Good Job' + (emoji.get('exclamation')) + (emoji.get('congratulations'))) } これでHIITのタイマー機能を実装することができました! 改善したい点 最後に改善したい点について書きます。 アドバイス等がありましたらコメントをいただけると嬉しいです! node_modules/hiit_timerのディレクトリに移動しなければ使えない 作成したnpmはmp3を使用しているので、mp3が入ってるnode_modules/hiit_timerに移動しないと使えないです。。 リファクタリングが不十分 もう少しスッキリしたコードになるんじゃないかと思うのですが、具体的にどうしたらいいのかわからず。。
- 投稿日:2021-10-26T21:52:32+09:00
【JavaScript】fileオブジェクトのファイル名を変更したオブジェクトを取得する
概要 JavaScriptではFileAPIを使用することで、クライアントPCからのファイルの読み込みを行うことができます。実装はJavaScript でファイルを読み込む方法の記事にのっています。 あまり無いケースだと思いますが、この受け取ったfileオブジェクトでのファイル名を変更する場合、どうすれば良いのかというのをメモ書きします。 対応 fileオブジェクトのファイル名を直接変更することはできません。 対応の一つとして、こちらのstackoverflowの記事にある通り、元のfileオブジェクトをベースにファイル名を変更して、新しくファイルオブジェクトを作成する方法が挙げられます。 実装サンプル 内容は上記のstackoverflowの記事とほぼ同様ですが、元の拡張子を取得して新しいファイルにも同様の拡張子を付与する実装を以下にのせます。 // ファイルはFileAPIで取得している前提 const fileName = inputFile.name; // ファイルの拡張子を取得 const fileExtention = fileName.substring(fileName.lastIndexOf(".") + 1); const blob = inputFile.slice(0, inputFile.size, inputFile.type); // ファイル名称変更後のファイルオブジェクト const renamedFile = new File([blob], "変更後のファイル名." + fileExtention, {type: inputFile.type});
- 投稿日:2021-10-26T21:44:22+09:00
【Vue.js】監視プロパティ(ウォッチャ)の基本
はじめに こんにちは! 今回は【Vue.js】監視プロパティ(ウォッチャ)の基本についてアウトプットしていきます! 監視プロパティとは 監視プロパティとは、特定のデータまたは、算出プロパティの状態を監視して変化があったときに登録した処理を自動的に実行できるものです。 書き方・解説 HTML <div id="app"> <p> {{ message }} </p> <p> <input type="text" v-model:value="message"> </p> <pre>{{ $data }}</pre> <!-- ⏫変更された内容がわかるように記述しておきます。 --> </div> Vue.js var app = new Vue({ el: "#app", data: { message: 'Hello Vue.js!' }, watch: { //⏫監視プロパティ(ウォッチャ) message: function(newValue, oldValue){ //⏫新しい値 ⏫変更前の値 console.log('new: %s , old: %s' , newValue,oldValue) //⏫newValue,⏫oldValueがコンソールされる。 } } }) 監視プロパティ(ウォッチャ)watchを定義し、`dataのmessage`の値に変更があったらconsoleにlogに新しい値と変更前の値を表示するプログラムを記述しました。 上記のようにテキストに「abc」と続けて値を変更していくと、以下のように新しく入力した値と入力する前の値がconsoleに出力されました。 まとめ ・監視プロパティ(ウォッチャ)とは、対象の監視物に変化があったとき記述した処理が自動的に実行されるものである。 最後に 今回は監視プロパティ(ウォッチャ)の基本についてアウトプットしました。 今回の記事を読んで質問、間違い等あればコメント等頂けると幸いです。 今後ともQiitaにてアウトプットしていきます! 最後までご愛読ありがとうございました!
- 投稿日:2021-10-26T18:38:23+09:00
【JavaScript】関数とオブジェクト⑪ new演算子
はじめに Udemyの【JS】ガチで学びたい人のためのJavaScriptメカニズムの講座の振り返りです。 前回の記事 目的 関数とオブジェクトについての理解を深める 本題 1.new演算子 new演算子とはコンストラクター関数からインスタンスを作成するための演算子のこと 例1 コンストラクター関数の戻り値がreturnで、オブジェクトになっている場合 // 関数を定義 function F(a,b){ this.a = a; this.b = b; // 戻り値にreturnで、空のオブジェクトを設定 return {}; } // インスタンス化 const instance = new F(1,2); // この結果を出力すると{}からのオブジェクトが出力される console.log(instance); // 戻り値{}がFに返ってきているから?? オブジェクトではなくプリミティブ型で戻り値を設定すると function F(a,b){ this.a = a; this.b = b; // オブジェクトではなくプリミティブ型で戻り値を設定 return 1; } const instance = new F(1,2); // 実行結果はF {a: 1, b: 2}となる console.log(instance); // returnを消しても同様の結果 prototypeで定義してみる function F(a,b){ this.a = a; this.b = b; } F.prototype.c = function(){} const instance = new F(1,2); console.log(instance); 実行結果. F {a: 1, b: 2}a: 1b: 2 [[Prototype]]: Object c: ƒ () constructor: ƒ F(a,b) [[Prototype]]: Object [[Prototype]]: Objectの中にcが入っている 例2 new演算子を呼び出す function F(a,b){ this.a = a; this.b = b; return {}; } F.prototype.c = function(){} // 第一引数をコンストラクタの「C」として定義 // 第二引数以下はコンストラクタ関数の引数によって変わってくるので...(レストパラメーターズ)と // 可変長の引数(固定ではなく任意の個数の引数)を表すためにargsを使用 function newOpe(C, ...args){ // 出力結果は以下の通り(上記のように表すと引数が配列として返ってくる) console.log(args); } // F(1,2)を削除し、新たにnewOpeという関数を定義 // 第一引数にコンストラクタ関数 const instance = newOpe(F,1,2) console.log(instance); Console. (2) [1, 2] 0: 1 1: 2 length: 2 [[Prototype]]: Array(0) 例3 thisが呼び出し元のオブジェクトのインスタンスになる場合 function F(a,b){ this.a = a; this.b = b; // return {}; } // thisというオブジェクトをprototypeの参照を保持したまま生成する F.prototype.c = function(){} function newOpe(C, ...args){ // 空のオブジェクト_thisを定義 createメソッドを使って渡ってきたCのprototypeをコピー const _this = Object.create(C.prototype); // Cを実行するとき_thisは関数Fのオブジェクト,argsは配列としてa,bが渡ってきている // それを変数resultに格納 const result = C.apply(_this, args); console.log(result, _this); // 戻り値でnewOpeに_thisの値を返す return _this; } const instance = newOpe(F,1,2); // 実行結果がF {a: 1, b: 2}となる console.log(instance); 今日はここまで! 参考にさせて頂いた記事 【JS】ガチで学びたい人のためのJavaScriptメカニズム
- 投稿日:2021-10-26T18:06:32+09:00
Nuxt3を触ってみたら本気を感じた
Nuxt3がベータになりましたね。 中身は色々変わったことが書かれているので、いちユーザーとして表面上何がどう変わったのかを見ていきたいと思います。 プロジェクト作成 新規プロジェクトは`nuxiというNuxt用の新しく作られたCLIを使います。 たった3コマンドでプロジェクトのテンプレートがもう使えちゃいます。 $ npx nuxi init nuxt3 $ cd nuxt3 $ yarn install この状態でnode modulesのインストールが完了するので、開発用サーバーを起動しましょう。 $ yarn dev -o -oオプション渡していたら以下のページが自動で開くはず。 開かなくても http://localhost:3000/ でいけますね。 ディレクトリ見てみる この状態のディレクトリ見てみるとかなりあっさりです(node周りは省略)。 /.nuxt - 生成されたVueのアプリがここに作られる。基本触らない。 app.vue - Nuxtのメイン(ルート)コンポーネント。 nuxt.config.ts - Nuxtの設定周りを記述するファイル。TSになった! tsconfig.json - /.nuxt配下にtsconfig.jsonを生成するために必要。良い感じになってるので基本はこのままで良さそう。 Nuxt2は/pagesとか/componentsとかディレクトリすべて生成されて中にREADME.mdが格納されていたんですが、かなりミニマルな作りになったみたいですね。自分でドキュメント読みながら追加していくのが良さそう。個人的にはこっちの方が使う側もドキュメント読みながら自分で取捨選択していくようになると思うので良いんじゃないかと思いました。 ドキュメント見てみる あとはドキュメント自体が読みやすくなりましたね。 ConceptsとDocumentsがキッチリ分かれるようになってます。 ディレクトリのアイコンが分かりやすく、アプリをデプロイする為のドキュメントもキッチリ揃ってます。 かなりDeveoloper's Experienceが考えられたカイゼンが見えてイイですね! Nuxtはディレクトリ構造がカッチリ決まってることが秩序をもたらしてくれるんですけど、 それぞれのディレクトリでどういう機能があるのかがディレクトリの名前更改も相まって理解しやすい。 pagesとcomponentsにコンポーネント作ってみる まずはpagesディレクトリを作りindex.vueを作ってみます。 /pages/index.vue <template> <div> <h1>INDEX</h1> </div> </template> このファイルを生成すると、開発サーバーが404になりました。理由はpagesディレクトリを検出時に.nuxt配下のアプリ生成がうまくいっていないか、pagesディレクトリを使うとvue-routerを使うようになるのでその切替がうまくいかないんだと思います。いったん、app.vue自体の修正も必要になるので、先に<NuxtWelcome/>コンポーネントではなく<NuxtPage/>コンポーネントに差し替えます。 app.vue <template> <div> <NuxtPage /> </div> </template> これで$ yarn dev -oし直すと、ちゃんとページが表示されました。 次はここに子コンポーネントを追加していきます。 componentsディレクトリを作り中にTitleComponent.vueを作ります。 /components/TitleComponent.vue <template> <h2>COMPONENT</h2> </template> そして、このコンポーネントを/pages/index.vue側で利用してみます。 /pages/index.vue <template> <div> <h1>INDEX</h1> <TitleComponent /> </div> </template> ドキュメント読むとなんとcomponentsディレクトリ配下のコンポーネントはすべて自動的にインポートされるらしいです。Nuxt2ではここは手動でインポートが必要でしたね。ここまでやってくれちゃうと最初にNuxt3触ってからVue触るとわけわからなくなりそうな気も。基本を理解しているなら裏で色々やってくれるのは早くてありがたいですけどね。 ここでまた開発サーバーのページを開くとエラーが出ます。どうやらNuxtの機能に関わるディレクトリの変更はホットリロードできないみたいですね。おとなしく$yarn dev -oし直すと、コンポーネントが表示されました。 感想 Nuxtというフレームワーク単体ではなく、CLI、ドキュメント、TypeScriptの導入など、総合的にDeveloper's Experienceのカイゼンを意識したエコシステムを目指し仕上げてきたなと言う印象を受けました。ここは個人的に素晴らしいポイントだと思っていて、そういうエコシステムにこそ健全なコミュニティが定着し、そのコミュニティがよりエコシステムを発展させていく良いライフサイクルが生まれることに繋がるはず。 とくにSSRのアプリのデプロイなんかは最初よくわからない人多いと思うんですが、それもメジャーなクラウドやホスティングサイトごとに説明が用意されてるのって親切ですよね。Vue3を少し触ってアプリ作るってなったらNuxt3でストレス少なく開発していくみたいな流れが良さそうです。
- 投稿日:2021-10-26T18:04:22+09:00
ニューヨークを拠点とするRevamp AgencyがWordPressショップからJamstackに切り替えた理由【後半】
Revamp AgencyがWordPressショップからJamstackに移行し、読み込みが速く、完全にカスタマイズ可能なウェブサイトで顧客を喜ばせるために、Bejamasがどのような支援をしたのかをお話いたします。 著者:Denis Kostrzewa 2019年1月23日 原文:https://bejamas.io/blog/revamp-wordpress-to-jamstack/ ③しかし、Revampのクライアントにとって、静的なウェブサイトは有効でしょうか? 静的サイトジェネレータは、この30年間で大きな進歩を遂げました。1990年代の静的なサイトは、基本的な機能しか備えていませんでしたが、現在の静的なサイトは、好きなようにダイナミックに変化させることができます。 静的なサイトでは、フロントエンドのコンテンツ表示の下にデータベース層がありません。静的サイトでは、ページを表示するためにデータベースからコンテンツが取り込まれるのを待つ必要はありません。 代わりに、静的ファイルを使用してブラウザ内にサイトを構築し、閲覧者がページにアクセスしたときにのみ表示されます(閲覧されていないページは表示されません)。 そのため、閲覧者は、問い合わせページであなたの電話番号を探そうとしているときに、グローバルフッターモジュールの下部にある要素が読み込まれるのを待つことはありません。 このツールセットは、データベースを使用して動的に構築された複雑なサイトよりも、重要な情報を潜在的な顧客に提供することに関心のある中小企業にとって理想的なサイト構築ツールです。About Us(会社概要)、Hours(営業時間)、Contact(お問い合わせ)、Connect(接続)などのページは、ほとんどのウェブサイトで最もアクセス数の多いページです。 「しかし、実際に導入してみると、その速さに驚かされました。」とWeisは言います。ほとんどの代理店のクライアントにとって、どんな技術がニーズを満たすかは問題ではありません。私たちの場合は、超高速サイトが大きな付加価値になりました。 James Weis Revamp Agency創業者兼リード開発者 ④WordPressからReactベースのGatsbyに乗り換えたときはどうでしたか? Revampチームは、まずJamstack Gatsbyで代理店のウェブサイトを再設計・再構築し、クライアントに展開する前に、最初から最後までのプロセスをテストすることにしました。 デザイナーは、自由に作業を進めることができました。WeisがRevampの新サイトの機能やルック&フィールの要件を提示したとき、特定のモジュールやプラグインの機能を開発者が組み込まなければならないというデザイン上の制限を受けることはありませんでした。 構築自体もシンプルでしたが、それはWeisがすでにJavascriptに精通しており、ReactとGraphQLを独学で学ぶための時間を割いたことが大きく影響しています。しかし、コードのコツを掴んだ後の開発作業は、WordPressのような不便なCMSプラットフォームの制限を考慮することなく、素直に行うことができました。 「最初のサイトだったので、デザインのプロセスをとても楽しみましたが、コードを覚えていくうちにペースが落ちてきました」とWeisは言います。「しかし、実際にやってみると、自分の思い通りのものを一から作ることができ、それはとても素晴らしいことでした。 Revampサイトでは、カスタムCMSの構築や、JamstackのCMSツールの多くを活用することはしませんでしたが、その方が早く立ち上げることができました。もちろん、ローンチ後の編集依頼は彼を通さなければならず、最初は手間がかかりましたが、クライアントによってはCMSを接続しないことが付加価値になることもあります。 「CMSを導入しない分、立ち上げまでの時間が大幅に短縮されたため、バックエンドへのログインに全く興味のないお客様にも、通常よりも早く新しいWebサイトをお届けし、社内の開発チームで編集を管理することができるようになりました」とWeisは語ります。 さらにWeisは、サイトが完成してから数ヶ月後、チームに時間があるときに、サイトをCMS(Revampは最初のGatsby CMSとしてDatoCMSを選んだ)に接続するのが非常に簡単だと感じました。クライアントの要望に応じてCMSを切り替えることも、Gatsbyのサイトでは簡単にできますので、コンテンツ管理の自由度が高まります。 ⑤社内の開発者を雇うことと、JamstackとGatsbyの専任開発者を雇うことの比較 新しいRevampのウェブサイトを立ち上げた後、チームは決断を迫られました。それは、社内の開発スタッフを活用して顧客のために新しいサイトの構築を展開するか、それとも第三者であるGatsbyの専用開発ショップを採用するかということでした。 「社内で技術のトレーニングに時間を割くことは有益でしたが、外注するという決断は私にとって何の問題もありませんでした。」 Revampチームのコアコンピタンスは、クライアントの目標やビジョンをグラフィック、アート、フォント、コピーに変えるデザインプロセスです。チームの各メンバーは、超専門的なスキルを持ち、クライアントに世界レベルのデザインを提供しています。 Jamstackのウェブサイト制作会社には、超専門的なスキルセットを持つチームメンバーがいるので、Revampチームは社内のチームメンバーのトレーニングを待つことなく、すぐに活用することができました。すべての代理店が知っているように、代理店が顧客のためにウェブサイトを構築し維持するために必要なすべてのスキルを持った1人または2人の開発者を見つけることは不可能です。開発専門のエージェンシーは、より広範なリソースを活用して、次から次へとやってくる課題に迅速かつ容易に対応することができます。 他の代理店では、開発業務を外部に委託するのではなく、社内で雇用することを選択するかもしれないが、Revampはその選択に満足している。チームは顧客とのデザインに集中し、JamstackとGatsbyのメリットをより多くの現在の顧客や見込み客に提供するために、より迅速に行動することができるようになりました。 ⑥Jamstackでサイトを構築することは、どんなビジネスにもメリットがあります。 どんなビジネスでもウェブサイトは有益ですが、時間がかかったり、不便だったり、管理や更新が困難なサイトは、良い結果を生むどころか害を及ぼします。消費者は、企業のブランドや声を伝える、きれいで、速くて、プロフェッショナルなウェブサイトに信頼を寄せます。Webサイトの読み込みに時間がかかりすぎると、消費者はそのドメインから離れてしまいます。Webサイトの存在に真剣に取り組み、必要な情報を簡単に得られるようにしている企業との取引を求めているのです。 JamstackとGatsbyのようなサイトジェネレーターは、ウェブとオンラインビジネスの未来を担うものです。 最後まで読んで下さり、ありがとうございました Jamstackに関心がある方はこちらまでお問合せください! 株式会社ヒューマンサイエンス https://www.science.co.jp/
- 投稿日:2021-10-26T17:47:42+09:00
はじめてのJavaScript⑫ 「配列と連想配列」
目次 1.はじめに 2.配列 3.配列の例題 4.多次元配列 5.多次元配列の例題 6.連想配列 7.連想配列の例題 8.おわりに 1. はじめに 本記事では、JavaScripの「配列」について記載する。 2. 配列 配列とは? ・複数のデータの集合を扱えるもの。 →1つの変数に対して、複数の値を格納できる。 ・要素にインデックス番号(添字)でアクセスできる。 3. 配列の例題 (例)変数colorsを定義し、配列の中から要素を取り出す。 配列の区切り方 ※添字は0から始まる。 ・カンマ区切りの値をブラケット[...]で囲った形式で表現する。 配列の定義 例の図から、以下のように表記できる。 index.js let colors = ['Red', 'Green', 'Blue', 'Yellow', 'Black']; 個々の要素の取り出し index.js 配列名[インデックス番号]; 例えば、配列からBlackを取り出してコンソールへ出力する場合は index.js console.log(colors[4]); となる。コンソールの出力結果は以下のようになる。 4. 多次元配列 多次元配列とは? 配列の中に配列を入れるデータ構造を指す。 言い換えれば、配列の中に複数の配列を格納できるということ。 5. 多次元配列の例題 複数の配列から要素を取り出す 変数scoreとして配列を組んでいく。多次元配列のインデックス番号は下図の通り。 インデックス番号の見分け方は、 最初の[]の数値が行で、最後の[]の数値が列となる。 配列の作成 例題の図を参照しながら配列を組んでいくと以下のようになる。 index.js let scores = [ [98, 100, 99], [80, 81, 97], [70, 96, 85] ]; ※カンマ区切りを忘れないこと!! 値の取り出し 多次元配列も配列同様、値の取り出し方はほぼ一緒だが、念の為に取り出し方法を記載しておく。 index.js 配列名[インデックス番号][インデックス番号] 図より、1,2(97点のスコア)を取り出してコンソールへ出力する場合は index.js console.log(scores[1][2]); となる。実際に出力された結果を見ると となる。 6. 連想配列 連想配列とは? ・各要素を文字列キーでアクセス可能な配列 ・Hash、Dictionary、Mapなどと呼ばれることもある。 7. 連想配列の例題 ユーザーの情報を取り出す 変数userとして個々の要素を取り出す。 配列の作成 表の中身を解説すると、 上段:key(キー) 下段:value(値) となる。 記述方法として、以下のように記述する。 index.js {キー名:値, キー名:値,・・・} 実際にJavaScriptで表記すると、 index.js let user = { name: '山田太郎', gender: '男性', birth: '1990/3/4' }; と記述する。 個々の要素の取り出し 取り出し方法は以下のようにする。 index.js オブジェクト名.プロパティ名 または オブジェクト名['プロパティ名'] これをコンソールへ出力し、nameを取り出したい場合は index.js console.log(user.name); // または console.log(user['name']); となる。 記述法は違うが出力される文字列は同じなので、同じ文字列が出力される。 8. おわりに 次項:はじめてのJavaScript⑬ 「配列の演習」に続く。
- 投稿日:2021-10-26T15:45:03+09:00
JavaScript - How to format a Date in MM/dd/yyyy HH:mm:ss format in JavaScript?
var dt = new Date(); console.log(`${ (dt.getMonth()+1).toString().padStart(2, '0')}/${ dt.getDate().toString().padStart(2, '0')}/${ dt.getFullYear().toString().padStart(4, '0')} ${ dt.getHours().toString().padStart(2, '0')}:${ dt.getMinutes().toString().padStart(2, '0')}:${ dt.getSeconds().toString().padStart(2, '0')}` );
- 投稿日:2021-10-26T14:45:42+09:00
Next.jsでIEブロックを行う
動作対象外のブラウザ(IE)でアクセスされた際、警告を出したい場合がありました。 Vue.jsの場合は、index.htmlに直に判定文を記述すればよかったのですが、Next.jsでのやり方がわからず苦戦しました。 調べてみると、当然ながらサポートしていないブラウザで動作させるのでNext.jsのアプリケーション内で制御するのはあまり良くなさそうなので、実現方法を考えてみました。 これ以外にも他にもっといい方法があるかもしれませんが、とりあえず残しておきます。 ※コードはTypeScriptです。 IE判定 こんな感じでメッセージを出したいが、pages/_app.tsxに記述するとエラーになる。 if (window.document.documentMode) { document.write('IEはサポートしていません') } _document.tsxの追加 そこで、_document.tsxを利用する。 _document.jsの詳細はこちら _document.tsx import NextDocument, { Html, Head, Main, NextScript } from 'next/document' export default class MyDocument extends NextDocument { render() { return ( <Html> <Head> <script async src="./scripts/checkBrowser.js" /> </Head> <body> <Main /> <NextScript /> </body> </Html> ) } } ブラウザの判定ロジックはpublic/scripts/checkBrowser.jsに記述する checkBrowser.js if (window.document.documentMode) { window.location.replace('../ie.html') } IEの場合、メッセージを表示する用のHTML(public/ie.html)を読み込む ie.html <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>Unsupported browser</title> </head> <body> <p> InternetExplorer(IE)はサポートされていません。最新のブラウザ(Edge)をご利用ください。 </p> </body> </html> まとめ _document.tsxを利用することで、どのURLにアクセスされてもブラウザ判定が可能
- 投稿日:2021-10-26T14:19:46+09:00
@google-cloud/connect-firestoreで保存されるセッションデータに作成時刻を追加する。
まえがき GAEでセッション管理にFirestoreを使うという内容のガイドがGoogleから公開されています。 Firestore でのセッション処理 | Node.js | Google Cloud 非常にわかりやすいのですが気になる事が一つ Connect-firestore は、古いセッションや期限切れのセッションを削除しません。Google Cloud Console でセッション データを削除するか、自動削除戦略を実装できます。セッションに、Memcache や Redis などのストレージ ソリューションを使用すると、期限切れのセッションが自動的に削除されます。 流石にコンソールから手作業で削除するのは面倒くさいので、古いセッションを自動で削除するようにしたい所。 要するにCloud MemorystoreやCloud SQLを使ってほしいということらしい。 しかしConnect-firestoreはデータをJSON文字列として保存する仕様のため、古いセッションの削除を行うにもクエリが使えない。なら保存時に作成時刻のフィールドを書き込むようにしてしまおうというのがこの記事の内容。 そもそもなんで作成時刻がないのか 実はissueが作成されたが特に何かあったわけでもなく終了している。 Session data cleanup · Issue #63 · googleapis/nodejs-firestore-session 曰く 「セッションデータの中に有効期限が入っているので別途作成時刻を含める必要はない。Firestore自体に自動削除機能は無いから必要性が薄い。」とのこと やること FirestoreStoreを継承したクラスを作り、setメソッドをオーバーライドする。 まずFirestoreStoreを継承してsetメソッドをオーバーライド Firestoreに書き込む際に作成時刻も含めるようにして、それをexportすればおk。 sessionStore.ts import { FirestoreStore, StoreOptions } from "@google-cloud/connect-firestore"; export class FirestoreStoreMod extends FirestoreStore { constructor(storeOption: StoreOptions) { super(storeOption); } set = async ( sid: string, session: unknown, callback?: ((err?: Error | undefined) => void) | undefined ): Promise<void> => { let sessJson; try { sessJson = JSON.stringify(session); } catch (err) { if (typeof callback === "function") { return callback(); } } const username: string | null = (session as any)?.passport?.user?.username || null; const createdDate = new Date(); // 本当はサーバータイムスタンプの方が良い。 await this.db .collection(this.kind) .doc(sid) .set({ data: sessJson, createdDate, username }) .then(() => { if (typeof callback === "function") { callback(); } }); }; } importして使う。 あとはガイドと同じようにsessionモジュールを読み込む際にimportして呼び出せばok。 index.ts import express from "express"; import session from "express-session"; import { Firestore } from "@google-cloud/firestore"; import { FirestoreStoreMod } from "./components/sessionStore"; const app = express(); // jsonの取り扱い用 app.use(express.json()); app.use(express.urlencoded({ extended: true })); const store = new FirestoreStoreMod({ dataset: new Firestore({ projectId: "ebikaniuni", keyFilename:"opabinia.json", }), kind: "sessions", }); // セッション app.use( session({ secret: "same", // dotenv等で別ファイル化+gitignoreに含める resave: false, saveUninitialized: false, cookie: { maxAge: 1 * 60 * 60 * 100, // ミリ秒で指定 sameSite: "strict", // ドメインが違うなら送信しない。 httpOnly: true, //httpリクエスト以外で送信されない secure: false, // 本番時は有効にする }, store,// 上で宣言したstore }) ); app.listen(3000, () => { console.log("server is started."); }); コンソールで見てこの様になっていれば成功 あとはcronなどで定期的に古いセッションを一括で削除する処理を追加すれば良いはず。 参考資料 Firestore でのセッション処理 | Node.js | Google Cloud Session data cleanup · Issue #63 · googleapis/nodejs-firestore-session @google-cloud/connect-firestore documentation
- 投稿日:2021-10-26T13:59:30+09:00
はじめてのJavaScript⑪ 「繰り返し処理の演習」
目次 1.はじめに 2.演習内容 3.実践 4.おわりに 1. はじめに 本記事では、JavaScriptの「繰り返し処理の演習」について記載する。 2. 演習内容 内容は以下の通り。 1〜100の整数、かつ、偶数の値について 合計値を計算してコンソールへ出力する。 演習の条件について、 ・繰り返し処理for文を利用 すること。 ※数値が偶数であることを判定するには、 数値を2で割ったときに割り切れるかどうか(余りが0)で確認できる。 3. 実践 まずは答えを開示する。 電卓アプリで計算したところ、1〜100までの偶数値を足していくと、2550になる。 変数の設定 変数名はsumとする。 sumはExcelの計算などで使用されることが多く、便宜上sumとしている。(この辺は任意で) index.js let sum = 0; sumに0が代入されている理由として、 数値を2で割ったときに割り切れるかどうか(割った数値が0になるため) というところが焦点として当てられているためである。 for文の設定 for文としては以下のようになる。 index.js for (let i = 1; i <= 100; i++) { } forの構文に関しては、以前記事にしたものを参照。 はじめてのJavaScript⑧ 「繰り返し処理 "for"」 初期化式:for文が実行されるときに最初の一回だけ実行される式なので、let i = 1となる。 ループ継続条件式:こちらに関しては変数iが100以下のときにループを継続するという意味合いでi <= 100となる。 増減式:最後のi++は、条件を満たすまで変数iに1ずつプラスするという意味である。 for文の中の処理 for文を記述しただけではこの例題は成り立たない。 条件分岐の観点から、if分を使用する。 index.js if (i % 2 == 0) { sum += i; } <解説> ・ifの()内のi % 2 == 0は、条件にあった ループで回した数値を2で割って0になるもの=偶数 という条件を分岐されるように記述したもの。 sum += iに関しては、 変数sum(初期値0)に対して1ずつプラスしたものが、for内の変数iと同じ数値になる というもの。 全て書き終えたものが以下となる。 index.js let sum = 0; for (let i = 1; i <= 100; i++) { if (i % 2 == 0) { sum += i; } } コンソールへ出力 index.js console.log(sum); 出力されたものは以下となる。 4. おわりに 次項:はじめてのJavaScript⑫ 「配列と連想配列」に続く。(現在作成中)
- 投稿日:2021-10-26T13:40:15+09:00
[JavaScript] 煩わしいURL整形処理とはおさらば!URL・クエリパラメータの操作
はじめに ちょっと前クエリパラメータの整形処理を独自実装した後、URLSearchParamsの存在を知って悲しい気持ちになりました。 そんな人が一人でも減るように、この記事ではJavaScriptのURL操作について記載します。 URL情報について URL情報は大きく分けて4つに分解できます。 URLの詳細について知りたい方はこちらの記事が参考になるかもしれません。 URLの基礎(初心者向けにわかりやすく解説) URLの構造 //qiitaのトレンド記事ページ https://qiita.com/trend?type=tag プロトコル・・・通信方式の部分(https://(http://)の部分) ホスト・・・アクセスする対象のサーバのアドレス(場所)を表す(qiita.com) パス・・・サーバの中の場所を表す(trend) クエリパラメータ・・・サーバ側へ伝える情報(?type=tag) URL情報の取得 それぞれの情報は Location インターフェースを用いて取得することができます。 取得対象 コード URL全体 window.location.href プロトコル window.location.protocol ホスト window.location.hostname パス window.location.pathname クエリパラメータ window.location.search URL情報の操作 URL情報の操作は URL インターフェースを使って効率的に行うことができます。 情報の取得 // window.location.href = https://qiita.com/trend?type=tag const url = new URL(window.location.href); // 全体 url.protocol // https://qiita.com/trend?type=tag // プロトコル url.protocol // https: // ホスト url.hostname // qiita.com // パス url.pathname // /trend // クエリパラメータ url.search // ?type=tag 情報の設定 クエリパラメータの操作は次の項で紹介します。 // window.location.href = https://qiita.com/trend?type=tag const url = new URL(window.location.href); // ホスト url.hostname = 'hoge.com'; // パス url.pathname = 'huga'; console.log(url.href); //https://hoge.com/huga?type=tag クエリパラメータの操作 クエリパラメータの操作はURLSearchParamsインターフェースを使うことで効率的に行うことができます。 ここでは代表的なメソッドをいくつか紹介します。 メソッド 概要 get() 指定したクエリパラメータの値を取得(最初の1つ)する getAll() 指定したクエリパラメータの値を全て取得(配列)する append() クエリパラメータの追加する set() 指定したクエリパラメータに値を設定する delete() 指定したクエリパラメータを全て削除する has() 指定したクエリパラメータが存在するかを真偽値で返す forEach() 全てのクエリパラメータ対してコールバック関数を介して処理ができる get(name) const url = new URL('https://qiita.com/search?q=javascript&sort=stock'); url.searchParams.get('sort'); //stock getAll(name) const url = new URL('https://qiita.com/search?q=javascript&sort=stock1&sort=stock2'); url.searchParams.getAll('sort'); //[stock1, stock2] append(name, value) const url = new URL('https://qiita.com/search?q=javascript&sort=stock1'); url.searchParams.append('test', 100); console.log(url.search); //?q=javascript&sort=stock1&test=100 set(name, value) 同一キー名が既にある場合は、その値を上書きする挙動をします。 const url = new URL('https://qiita.com/search?q=javascript&sort=stock'); url.searchParams.set('test',100); url.searchParams.set('sort','update'); console.log(url.search); //?q=javascript&sort=update&test=100 delete(name) const url = new URL('https://qiita.com/search?q=javascript&sort=stock'); url.searchParams.delete('sort'); console.log(url.search); //?q=javascript has(name) const url = new URL('https://qiita.com/search?q=javascript&sort=stock'); url.searchParams.has('sort'); //true url.searchParams.has('hogehoge'); //false forEach() const url = new URL('https://qiita.com/search?q=javascript&sort=stock'); url.searchParams.forEach((value, key) => { console.log(key, value); }); // q javascript // sort stock さいごに 結論、クエリパラメータの操作は URLSearchParams を使うとスムーズです!
- 投稿日:2021-10-26T13:15:33+09:00
グローバル空間の汚染と即時関数
グローバル空間の汚染 グローバル空間の汚染とは、グローバルスコープの変数や関数が存在すること。 グローバルスコープは、プログラムのどこからでもアクセス可能なため、他のプログラムなどの変数名の衝突が発生し、予期せぬバグが発生してしまう。 グローバル空間を汚染しないために、グローバル空間には変数及び関数を宣言すべきではない。 それを防ぐ手段の1つが即時関数を使用すること。即時関数で囲むことでスコープをつくり、アクセスを制限することができる。 即時関数とは 即時関数とは、関数定義と関数の実行が同時に行われる無名関数のこと。 これを使うとグローバル空間の汚染を避けることができる。 即時関数の書き方は以下となる。 書き方 (function() { // 処理内容 })(); // ラムダ式を使った書き方 (() => { // 処理内容 })(); これにより、即時関数内で宣言された変数は関数スコープとなり、関数の外から変数にアクセルすることができない。
- 投稿日:2021-10-26T10:38:07+09:00
fullCalendar dayGridWeek で週変更ボタン(<,>)を日付レベルで変更できるようにする
FullCalendar v5.10.0 Angular,React,Vue,といったフレームワークにも対応した便利なカレンダーライブラリ。 今回はフレームワークは使用していない環境下での話ですが、参考になればと。 nodejs環境下であるため、プラグインの宣言方法など違いがあるかもしれません。 週単位で閲覧範囲が遷移する仕様 initialViewをdayGridWeekに設定すると、 デフォルトで<,>のボタンが設置され、押下すると次週に遷移する。 例:10月 >押下前 1(Fri) 2(Sat) 3(Sun) 4(Mon) 5(Tue) 6(Wed) 7(Thu) >押下後 8(Fri) 9(Sat) 10(Sun) 11(Mon) 12(Tue) 13(Wed) 14(Thu) 日付単位で表示範囲を変更したい 例:10月 >押下前 1(Fri) 2(Sat) 3(Sun) 4(Mon) 5(Tue) 6(Wed) 7(Thu) >押下後 2(Sat) 3(Sun) 4(Mon) 5(Tue) 6(Wed) 7(Thu) 8(Fri) 解決策 customButtons、headerToolbarで解決。 const date = new Date(); const calendar = new Calendar(document.getElementById('your-custom-id'), { plugins: [dayGridPlugin], initialView: 'dayGridWeek', locale: 'ja', firstDay: date.getDay(), customButtons: { nextDate: { text: '>', click: () => { date.setDate(date.getDate() + 1); calendar.setOption('firstDay', date.getDay()); calendar.gotoDate(date); } }, prevDate: { text: '<', click: () => { date.setDate(date.getDate() - 1) calendar.setOption('firstDay', date.getDay()); calendar.gotoDate(date); } } }, headerToolbar: { left: 'prevDate,nextDate', center: 'title', right: '' } }); 解説 標準で用意されているボタンを非表示にして、カスタムボタンで対応。 ・日付型データを作成 ・firstDayにgetDayの値(曜日)を入れる。 カスタムボタンで<,>を作成し、クリックイベントで ・dateの加減算 ・setOptionメソッドでカレンダーのfirstDayを更新、(ココがミソ) ・gotoDateメソッドでカレンダーをdateの日付に移動。 ライブラリの標準機能にないのかなぁ、。(見つけてないだけ??)
- 投稿日:2021-10-26T09:57:55+09:00
React + TypeScript: setInterval()をReactのプログラミングモデルに合わせてフックに書き替える ー useInterval
Reactのとくに関数コンポートでsetInterval()を使うと、やっかいに巻き込まれることが少なくありません。Reactのプログラミングモデルと相性がよくないからです。そこで、面倒なことを考えずに済むように、フック(useInterval)に書き替えてみましょう(サンプル001)。 サンプル001■useIntervalフックを使ったカウンターの作例 >> CodeSandboxへ 本稿の作例は、Create React AppでReactアプリケーションのひな型をつくりました。TypeScriptも組み込むため、コマンドラインツールでnpx create-react-app プロジェクト名に、オプション--template typescriptを添えます(「Create React AppでTypeScriptが加わったひな形アプリケーションをつくる」参照)。 setInterval()のどこが煩わしいのか setInterval()でやっかいに巻き込まれるコード例をつぎに示します。1秒ごとにカウントアップするカウンターです。副作用ですので、useEffectフックに定め、クリーンアップの処理(clearInterval())はコールバック関数にして返します。今回の作例では、ひたすらカウントアップをし続けるだけです。つまり、setInterval()ははじめに1度呼び出せばよいので、useEffectフックの第2引数、依存配列は空([])にしました。 src/App.tsx import React, { useEffect, useState } from 'react'; function App() { const [count, setCount] = useState(0); const [delay, setDelay] = useState(1000); useEffect(() => { const interval = setInterval(() => { console.log(count); // 出力: 0 setCount(count + 1); }, delay); return () => clearInterval(interval); }, []); return ( <> <h1>{count}</h1> </> ); } export default App; 実行すると、カウンターの数値は0から1になったまま変わりません。インターバルの加算が止まったのかとブラウザのコンソールを見ると、変数(count)の値として0が何度も出力されています(console.log())。つまり、処理そのものは繰り返されており、ただもとの数値が0なので、加算した1が設定されているということです。 なぜ、インターバルのカウンター(count)数値は更新されないのでしょう。それは、はじめに副作用(useEffect)が実行されたとき、setInterval()のコールバック関数は状態変数(count)の値をクロージャに保持してしまい、インターバルのたびに新たな状態変数値を参照し直さないからです。 これを避けるには、useEffectの第2引数の依存配列に状態変数(count)を加えることが考えられます。状態変数が変わるたびに、クリーンアップの処理が行われ、新たな変数値にもとづいてsetInterval()が呼び出されるということです1。 src/App.tsx function App() { useEffect(() => { const interval = setInterval(() => { setCount(count + 1); }, delay); // }, []); }, [count]); } もうひとつ、状態変数の設定関数(setCount)呼び出しを関数型の更新にする手もあります。引数の関数に渡されるのは、最新の状態変数値です。その値に加算して返せばカウンターは正しくカウントアップされます。 src/App.tsx function App() { useEffect(() => { const interval = setInterval(() => { // setCount(count + 1); setCount((count) => ++count); }, delay); }, []); } けれど、本稿のお題は、このようなやっかいごとに巻き込まれずに済むインターバルのカスタムフック(useInterval)を定めることです。順を追って考えてゆきましょう。 setInterval()の処理をフックuseIntervalに書き替える インターバルのカスタムフックuseIntervalは、つぎのように副作用(useEffect)をフック内部に取り込みます。引数はsetInterval()と同じ、コールバック関数(callback)とインターバルミリ秒(delay)です。後者はsetInterval()に渡すとき、デフォルト値を0にしました。 src/useInterval.ts import { useEffect } from 'react'; const useInterval = (callback: Function, delay?: number) => { useEffect(() => { const interval = setInterval(() => callback() , delay || 0); return () => clearInterval(interval); }, [callback, delay]); } export default useInterval; フックuseIntervalは、ルートモジュールsrc/App.tsxから、コンポーネント(App)内でつぎのように単純に呼び出すだけです。副作用はフックが扱いますから、煩わされることはありません。 src/App.tsx // import React, { useEffect, useState } from 'react'; import React, { useState } from 'react'; import useInterval from './useInterval'; function App() { /* useEffect(() => { const interval = setInterval(() => { console.log('render:', count); setCount(count + 1); }, delay); return () => clearInterval(interval); }, []); */ useInterval(() => { console.log('render:', count); // 確認用 setCount(count + 1); }, delay); } useIntervalフックの引数でインターバルの間隔を変える フックuseIntervalでは、インターバルの間隔(delay)を副作用(useEffect)の依存配列に加えました。それは、フックを使う側から、間隔が自由に変えられるということです。そこで、ルートモジュールsrc/App.tsxのコンポーネント(App)には、つぎのように数値の入力フィールド(<input type="number">)を加えて、インターバルのミリ秒が設定できるようにしました。 src/App.tsx function App() { const handleDelayChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { setDelay(Number(event.target.value)); } return ( <> <input type="number" value={delay} onChange={handleDelayChange} /> </> ); } 書き替えるのはこのルートモジュール(src/App.tsx)の修正だけです。フックuseIntervalに手は加えません。これだけで、入力フィールドの数値で、インターバルの間隔が変わるようになりました。 インターバル処理を一時停止する つぎは、フックuseIntervalに新たな機能を加えましょう。インターバルの処理を一時停止することです。フックの第2引数(delay)をnullに設定したとき、一時停止とします。といっても書き替えは、つぎのようにフックの第2引数の型づけを改め、条件判定をひとつ加えるだけです。 src/useInterval.ts // const useInterval = (callback: Function, delay?: number) => { const useInterval = (callback: Function, delay?: number | null) => { useEffect(() => { if (delay !== null) { const interval = setInterval(() => callback() , delay || 0); } }, [callback, delay]); } ルートモジュール(src/App.tsx)のコンポーネント(App)には、チェックボックス(<input type="checkbox">)を加えて、値は状態変数(isRunning)に定めました。フックuseIntervalの第2引数をこの変数で切り替えれば、インターバルの処理が一時停止できるのです。 src/App.tsx function App() { const [isRunning, setIsRunning] = useState(true); useInterval(() => { // }, delay); }, isRunning ? delay : null); const handleIsRunningChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { setIsRunning(event.target.checked); } return ( <> <h1>{count}</h1> <input type="checkbox" checked={isRunning} onChange={handleIsRunningChange} /> Running <br /> </> ); } これで一旦、フックuseIntervalの動きはできました。ルートモジュールsrc/App.tsxと合わせて、つぎのコード001にそれぞれの記述全体をまとめましょう。 コード001■ useIntervalフックを使ったカウンターサンプル src/App.tsx import React, { useState } from 'react'; import useInterval from './useInterval'; function App() { const [count, setCount] = useState(0); const [delay, setDelay] = useState(1000); const [isRunning, setIsRunning] = useState(true); useInterval(() => { console.log('render:', count); setCount(count + 1); }, isRunning ? delay : null); const handleDelayChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { setDelay(Number(event.target.value)); } const handleIsRunningChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { setIsRunning(event.target.checked); } return ( <> <h1>{count}</h1> <input type="checkbox" checked={isRunning} onChange={handleIsRunningChange} /> Running <br /> <input type="number" value={delay} onChange={handleDelayChange} /> </> ); } export default App; src/useInterval.ts import { useEffect } from 'react'; const useInterval = (callback: Function, delay?: number | null) => { useEffect(() => { if (delay !== null) { const interval = setInterval(() => callback() , delay || 0); return () => clearInterval(interval); } }, [callback, delay]); } export default useInterval; コールバック関数をRefに設定する フックuseIntervalの副作用の依存配列を、改めて見直します。インターバル間隔(delay)はよいとして、コールバック(callback)が変わったからといってsetInterval()を呼び直さなくてもよいはずです。関数の参照さえ改めれば済みます。 そういうときに用いるのがRefオブジェクトです(「インスタンス変数のようなものはありますか?」参照)。Refオブジェクトのcurrentプロパティは、レンダーによって改められることがなく、値が変わっても再描画は引き起こしません(「useRef」参照)。 そこで、副作用(useEffect)をコールバック(callback)とインターバル間隔(delay)でつぎのように分けます。コールバックはRefオブジェクト(savedCallback)のcurrentプロパティ値の参照を改めるだけです。レンダーはし直しません。インターバル間隔が変わったときに、setInterval()を呼び出し直して再描画します。 src/useInterval.ts // import { useEffect } from 'react'; import { useEffect, useRef } from 'react'; const useInterval = (callback: Function, delay?: number | null) => { const savedCallback = useRef<Function>(() => {}); useEffect(() => { savedCallback.current = callback; }, [callback]); useEffect(() => { if (delay !== null) { const interval = setInterval(() => // callback() savedCallback.current() , delay || 0); } // }, [callback, delay]); }, [delay]); } 書き改めたフックuseIntervalの記述を、つぎのコード002に掲げます。実は、このコードは、react-useのuseIntervalをもとにしました。フックがつくられたきっかけは、Dan Abramov氏のblog記事「Making setInterval Declarative with React Hooks」です。実装は、細かいところが少し異なります。さらに、本稿ではコールバック(savedCallback)に対する副作用の依存(callback)を加えました(「Should only run effect when callback changes」参照)。実際のコードの動きは、冒頭に掲げたサンプル001のCodeSandbox作例をご参照ください。 コード002■コールバック関数をRefに設定したuseIntervalフック src/useInterval.ts import { useEffect, useRef } from 'react'; const useInterval = (callback: Function, delay?: number | null) => { const savedCallback = useRef<Function>(() => {}); useEffect(() => { savedCallback.current = callback; }, [callback]); useEffect(() => { if (delay !== null) { const interval = setInterval(() => savedCallback.current() , delay || 0); return () => clearInterval(interval); } return undefined; }, [delay]); } export default useInterval; このコード例では、インターバルのたびに変数値がカウントアップされ、クリーンアップのあとsetInterval()が呼び直されます。ですから、setTimeout()(クリーンアップはclearTimeout())に書き替えても動きは同じです。 ↩
- 投稿日:2021-10-26T08:39:01+09:00
[Snippet] JavaScript、Node.js
これは何? JavaScriptで「あれってどう書くんだっけ?」を集めたメモです。 時間系 Sleep Return: [void] const sleep = msec => new Promise(resolve => setTimeout(resolve, msec)) UNIX timeを取得 Return: [number]: 1635204475862 (unit: millisecond) Date.now() 文字列として時間を取得 Inputs: TIMESTAMP_MSEC (unit: millisecond): [number]: 1635204475862 Return: [string]: "Tue Oct 26 2021 08:27:55 GMT+0900 (Japan Standard Time)" new Date(TIMESTAMP_MSEC); Timezoneを考慮した時間を取得 Return: [string]: "2021-10-26T20:57:57.911+09:00" (Format: ISO_8601) const getDateNow = () => { const date = new Date() const timeOffset = date.getTimezoneOffset() const sign = (timeOffset)<=0 ? '+' : '-' const rTimeOffset = Math.abs(timeOffset) const tz = `${sign}${('00' + Math.floor(rTimeOffset/60)).substr(-2)}:${('00' + rTimeOffset%60).substr(-2)}` return new Date(date.getTime() - (timeOffset * 60000)).toJSON().replace(/Z$/, tz) } File操作系 ディレクトリ作成(再帰的) Arguments: DIR_NAME: [string]: "/home/hoge/download" Return: [void] const fs = require('fs-extra'); try { fs.mkdirSync(`${DIR_NAME}`, { recursive: true }) } catch(e) { console.error(e.message); } ファイル存在確認 Arguments: FILE_NAME: [string]: "/home/hoge/download/test.txt" Return: [Boolean] const fs = require('fs-extra'); try { if (fs.existsSync(`${FILE_NAME}`)) { // アリ } else { // ナシ } } catch(e) { console.error(e.message); } ファイルを書き出す Arguments: FILE_NAME: [string]: "/home/hoge/download/test.txt" CONTENT_TEXT: [string]: "aaaa\nbbbb\ncccc" Return: [Boolean] const fs = require('fs-extra'); try { fs.writeFileSync(`${FILE_NAME}`, `${CONTENT_TEXT}`) } catch(e) { console.error(e.message); } ファイルの属性取得 Arguments: FILE_NAME: [string]: "/home/hoge/download/test.txt" Return: [object]: class-fsstats const fs = require('fs-extra'); try { const fileStat = fs.statSync(`${FILE_NAME}`) } catch(e) { console.error(e.message); }
- 投稿日:2021-10-26T07:12:21+09:00
React×TypeScriptで作ったポートフォリオサイトの説明
作成したサイト 実現したいこと ・自分の経歴、能力、作品などが伝わるポートフォリオサイトの作成 ・SPAによる高速なページ遷移 ・必要な人のみ閲覧してもらえばいいのでSEO対策は考えない ・学習コストが増えすぎるのを防ぐため、サーバーサイドは考慮しなくていい構成にする ・同様の理由で必要以上のフレームワーク、ライブラリを導入しすぎないようにする ・レスポンシブ対応の実装 ・チーム開発を意識したコーディングを心掛ける 使用技術 フロントエンド React, React-Router, React-Hook-Form, EmailJS, TypeScript, styled-component, styled-media-query, Material-UI, react-vertical-timeline-component Yarn, Prettier ツール Git, GitHub, git-Flow, GitHub-Pages 個人的に今一番人気があると感じているJavaScriptライブラリであるReactと、今後は新規開発で使われることになりそうなTypeScriptを採用しました。cssライブラリとしてコンポーネント指向と相性の良いstyled-componentsを採用しました。あまりデザインに時間をかけすぎたくなかったのでMaterial-UIも採用しています。ホスティングはGitHub-Pagesで行っています。 ディレクトリ構成 ディレクトリ構成はcreate-react-appコマンドで作成したプロジェクトディレクトリにatomic designを適用して決めました。organismsやmoluculesは将来的に分割が予想されるコンポーネントも配置しています。コンポーネントを分割する際は再利用性がある場合と可読性の向上のための2つの場合に分けて行いました。 reactPortfolio ├── build ├── node_modules ├── package.json ├── public │ └── index.html ├── README.md ├── src │ ├── App.tsx │ ├── assets │ │ ├── data //配列などのデータ格納ディレクトリ │ │ ├── images //画像格納ディレクトリ │ │ ├── styles │ │ │ ├── media.tsx //styled-media-queryのラッパーファイル │ │ │ └── theme.tsx //Material-UI用のカラーテーマファイル │ │ └── Type.tsx │ ├── components │ │ ├── atoms │ │ ├── molecules │ │ ├── organisms │ │ ├── pages │ │ └── templates │ ├── index.tsx │ ├── react-app-env.d.ts │ └── ComponentRouter.tsx //ルーターファイル ├── tsconfig.json ├── types │ └── import-jpg.d.ts └── yarn.lock コーディング規則 型定義 ・関数コンポーネントにはアロー関数を使い、型定義は「VFC」で行う。 ・childrenを使いたい場合は"PropsType"に型定義して使うこと。 ・基本的に関数コンポーネントの返り値に型注釈はつけない。 ・anyは使用禁止。 スタイル ・一行で済むスタイリングも基本的にはstyled-coponentsでスタイルコンポーネントを作成する。 ・スタイルが2行以上に拡張される確率が非常に低いと判断される場合はインラインスタイルを使用してもよい。 ・スタイルコンポーネントは関数コンポーネントの後に記述し、登場するスタイルコンポーネントの順に書く ・レスポンシブ対応はstyled-media-queryを用いて行い、レスポンシブ対応しているcssプロパティは下の部分に寄せて改行する。 命名規則 ・スタイルコンポーネントの名前は"S + キャメルケースの名称"とする。 ・複数要素を囲うタグの名前は”意味を推測しやすい名前 + Container”とする。"Wrapper"は混乱を避けるため利用しない。 ・コンポーネント全体を囲うタグの名前は”SComponentContainer”とする。 ・命名は"Container"などを含めて4単語までのキャメルケースで行い、5単語以上になる場合は1単語を省略するか異なる命名を考える。 ・型定義の末尾には"Type"とつける。 ・propsの型名は"PropsType"とする。 その他 ・短絡評価によるコンポーネントの表示、非表示は行わず、三項演算子で実現する。 ・importのエリアはライブラリ、material-uiなどのスタイル、自作関数コンポーネントや型定義や配列データ、に分けて改行を入れる。 ・importの3つ目のエリア内では一番上が型定義、その次が配列や画像などのデータ、最後に自作関数コンポーネントの順に記述する。 ・コンポーネント内のreturn文の前の定数宣言同士に改行をいれない。 ・将来的に数が大きくなる可能性がある定数配列などはdataフォルダに格納し、インポートして使う。 工夫した点 atomic designによるディレクトリ構成 atomic designを利用することでコンポーネントがどのように利用されるのかが分かりやすくなり、可読性も向上しました。 コーディング規則による統一性 自分以外の人間がコーディングをしたとしても同じようなコーディングになるように自分なりに規則を決めてコーディングしました。 styled-media-queryを用いたレスポンシブ対応 そのまま記述することも考えましたが、ブレイクポイントを数値で書くのは非常に危険だと考え、別ファイルに書いてインポートするなども考えましたが少し手間でした。何か良いライブラリがないかと探した際にstyled-media-queryを見つけましたが、そもそもの記述が少し冗長だったのでラップして短く、安全にレスポンシブ対応を行うことが出来ました。今回のポートフォリオではブレイクポイントを1170pxと768pxの2つに設定してレスポンシブ対応を行っています。 //そのままのstyled-media-query const SText = styled.h1` font-size: 64px; ${media.between("medium","large")` font-size: 36px; `} ${media.lessThan("medium")` font-size: 26px; `} `; //ラップして簡略化したもの const SText = styled.h1` font-size: 64px; ${media.lg` font-size: 36px; `} ${media.md` font-size: 26px; `} `; 簡潔で分かりやすいデザイン Material-UIやreact-vertical-timeline-componentを利用した簡潔で分かりやすいデザインを心掛けました。 反省点 レスポンシブ対応がモバイルファーストでない モバイルファーストで設計した方が良いことは知っていたのですが、具体的にどうすれば良いのかわからずPCをベースにスタイリングしていった結果、あとから大幅な修正をすることになりました。 おわりに モダンな技術を用いてポートフォリオサイトを作成しました。作ってみないと分からないことがたくさんあったので良い経験になりました。次はサーバーサイドの技術を含めた作品を作りたいと思います。 参考文献
- 投稿日:2021-10-26T07:12:21+09:00
React×TypeScriptで作ったポートフォリオサイトを作成した
はじめに React、TypeScriptを使った初めての作品として自己紹介サイトを作成しました。 作成したサイト 実現したいこと ・自分の経歴、能力、作品などが伝わるポートフォリオサイトの作成 ・SPAによる高速なページ遷移 ・必要な人のみ閲覧してもらえばいいのでSEO対策は考えない ・学習コストが増えすぎるのを防ぐため、サーバーサイドは考慮しなくていい構成にする ・同様の理由で必要以上のフレームワーク、ライブラリを導入しすぎないようにする ・レスポンシブ対応の実装 ・チーム開発を意識したコーディングを心掛ける 使用技術 フロントエンド React, React-Router, React-Hook-Form, EmailJS, TypeScript, styled-component, styled-media-query, Material-UI, react-vertical-timeline-component Yarn, Prettier ツール Git, GitHub, git-Flow, GitHub-Pages 個人的に今一番人気があると感じているJavaScriptライブラリであるReactと、今後は新規開発で使われることになりそうなTypeScriptを採用しました。cssライブラリとしてコンポーネント指向と相性の良いstyled-componentsを採用しました。あまりデザインに時間をかけすぎたくなかったのでMaterial-UIも採用しています。ホスティングはGitHub-Pagesで行っています。 ディレクトリ構成 ディレクトリ構成はcreate-react-appコマンドで作成したプロジェクトディレクトリにatomic designを適用して決めました。organismsやmoluculesは将来的に分割が予想されるコンポーネントも配置しています。コンポーネントを分割する際は再利用性がある場合と可読性の向上のための2つの場合に分けて行いました。 reactPortfolio ├── build ├── node_modules ├── package.json ├── public │ └── index.html ├── README.md ├── src │ ├── App.tsx │ ├── assets │ │ ├── data //配列などのデータ格納ディレクトリ │ │ ├── images //画像格納ディレクトリ │ │ ├── styles │ │ │ ├── media.tsx //styled-media-queryのラッパーファイル │ │ │ └── theme.tsx //Material-UI用のカラーテーマファイル │ │ └── Type.tsx │ ├── components │ │ ├── atoms │ │ ├── molecules │ │ ├── organisms │ │ ├── pages │ │ └── templates │ ├── index.tsx │ ├── react-app-env.d.ts │ └── ComponentRouter.tsx //ルーターファイル ├── tsconfig.json ├── types │ └── import-jpg.d.ts └── yarn.lock コーディング規則 型定義 ・関数コンポーネントにはアロー関数を使い、型定義は「VFC」で行う。 ・childrenを使いたい場合は"PropsType"に型定義して使うこと。 ・基本的に関数コンポーネントの返り値に型注釈はつけない。 ・anyは使用禁止。 スタイル ・一行で済むスタイリングも基本的にはstyled-coponentsでスタイルコンポーネントを作成する。 ・スタイルが2行以上に拡張される確率が非常に低いと判断される場合はインラインスタイルを使用してもよい。 ・スタイルコンポーネントは関数コンポーネントの後に記述し、登場するスタイルコンポーネントの順に書く ・レスポンシブ対応はstyled-media-queryを用いて行い、レスポンシブ対応しているcssプロパティは下の部分に寄せて改行する。 命名規則 ・スタイルコンポーネントの名前は"S + キャメルケースの名称"とする。 ・複数要素を囲うタグの名前は”意味を推測しやすい名前 + Container”とする。"Wrapper"は混乱を避けるため利用しない。 ・コンポーネント全体を囲うタグの名前は”SComponentContainer”とする。 ・命名は"Container"などを含めて4単語までのキャメルケースで行い、5単語以上になる場合は1単語を省略するか異なる命名を考える。 ・型定義の末尾には"Type"とつける。 ・propsの型名は"PropsType"とする。 その他 ・短絡評価によるコンポーネントの表示、非表示は行わず、三項演算子で実現する。 ・importのエリアはライブラリ、material-uiなどのスタイル、自作関数コンポーネントや型定義や配列データ、に分けて改行を入れる。 ・importの3つ目のエリア内では一番上が型定義、その次が配列や画像などのデータ、最後に自作関数コンポーネントの順に記述する。 ・コンポーネント内のreturn文の前の定数宣言同士に改行をいれない。 ・将来的に数が大きくなる可能性がある定数配列などはdataフォルダに格納し、インポートして使う。 工夫した点 atomic designによるディレクトリ構成 atomic designを利用することでコンポーネントがどのように利用されるのかが分かりやすくなり、可読性も向上しました。 コーディング規則による統一性 自分以外の人間がコーディングをしたとしても同じようなコーディングになるように自分なりに規則を決めてコーディングしました。 styled-media-queryを用いたレスポンシブ対応 そのまま記述することも考えましたが、ブレイクポイントを数値で書くのは非常に危険だと考え、別ファイルに書いてインポートするなども考えましたが少し手間でした。何か良いライブラリがないかと探した際にstyled-media-queryを見つけましたが、そもそもの記述が少し冗長だったのでラップして短く、安全にレスポンシブ対応を行うことが出来ました。今回のポートフォリオではブレイクポイントを1170pxと768pxの2つに設定してレスポンシブ対応を行っています。 //そのままのstyled-media-query const SText = styled.h1` font-size: 64px; ${media.between("medium","large")` font-size: 36px; `} ${media.lessThan("medium")` font-size: 26px; `} `; //ラップして簡略化したもの const SText = styled.h1` font-size: 64px; ${media.lg` font-size: 36px; `} ${media.md` font-size: 26px; `} `; 簡潔で分かりやすいデザイン Material-UIやreact-vertical-timeline-componentを利用した簡潔で分かりやすいデザインを心掛けました。 反省点 レスポンシブ対応がモバイルファーストでない モバイルファーストで設計した方が良いことは知っていたのですが、具体的にどうすれば良いのかわからずPCをベースにスタイリングしていった結果、あとから大幅な修正をすることになりました。 おわりに モダンな技術を用いてポートフォリオサイトを作成しました。作ってみないと分からないことがたくさんあったので良い経験になりました。次はサーバーサイドの技術を含めた作品を作りたいと思います。 参考文献
- 投稿日:2021-10-26T06:50:37+09:00
独学でタスク管理サービスFroteをポートフォリオとして開発した
はじめに 現在情報系の大学院1年生のつむぎといいます。web業界に行きたいと思い、フロントエンジニアのポートフォリオとしてタスク管理サービスFroteを独学で開発しました。まだ完成とは程遠いですが、今回はとりあえずサービスが公開出来るまでの過程を書いていきたいと思います。作成したものはこちらです(初回アクセス時はかなり時間かかるかも)[Frote] [github] 開発しようと思った背景 予算的、技術的に一般ユーザーが満足するクオリティのものは作れないと思ったので、自分が欲しいものを作ろうと決めました。毎日のタスクをvscodeのテキストファイルで管理していたのですが、問題点が大きくわけて2つありました。1つは依存関係のあるタスク同士が分かりにくいという問題です。Aが終わらないとBが出来ない状態を「BはAに依存している」と定義するとAとBは並列の関係にあるべきではありません。つまり、AのほうがBより優先度は高いですが、あたかも同じ程度の優先度に見えてしまっていました。2つ目は優先度の決定に時間がかかるという問題です。依存関係も気にしつつ、こちらのほうが優先度が高いななどと判断する必要がありました。後からタスクを追加する場合もどこに入れようかなどで悩み、結果として時間がかかっていました。 この2つの問題点を解決できるようなtodoアプリは僕が探した感じは見つからなかったので、僕が作ろうと考えた次第です。Frote(フローテ)はFree priorityからフランス語のprioriteを混ぜて命名しました。 開始時のスキル 大学でCとDBをがっつりとJavaを少し、あとはatcoderでC++を趣味程度で触っているくらいしか知識がありませんでした。html,css,javascriptはhello worldが出来るレベル。 要件定義 ・自分の技術力をアピール出来るようなもの ・タスクの依存関係の可視化、優先度の自動決定が出来るタスク管理サービス ・お金は極力かけない ・時間の関係上学習コストは出来る限り少なくしたい ・レスポンシブ対応 技術選定 React 今の流行り的にSPAはやりたいと思い、採用しました。 TypeScript C言語をやっていたせいか静的型付言語っぽい方が好きなので採用しました。 styled-components コンポーネント志向と相性の良いCSS in JSの中で有名なのを採用しました。tailwindcssなども考えましたが、最初は生のcssを触りたかったのでこちらにしました。 material-ui reactのUIコンポーネントライブラリとして定番なものを選びました。 recoil 状態管理はrecoilでやっています。最初はuseContextでやっていたのですが、大変だったので移行しました。 Laravel(php) バックエンド言語は悩みましたがphpにしました。nodejsとGOは最初に触るのには不安がありましたし、railsはSPAが得意そうな印象があまり無かったです。スクレイピングなどもする予定が無かったので、phpと一番人気のフレームワークlaravelを採用しました。 heroku 本当はAWSにしたかったのですが、費用と学習コストを考えてherokuにデプロイすることにしました。 mySQL スタンダードなものを採用しました その他使用技術 react-roter,react-hook-form,styled-media-query,vscode,prettier,npm,webpack, Babel,Composer,Git,GitHub DockerやCircle CI、nextjsなども使いたかったのですが、一度に手を出しすぎると大変そうだったので今回は断念しました。 基本設計 優先度の決定 パラメータなしはきついので、緊急度と重要度というパラメータをタスク追加時に決めてもらう。 依存関係の可視化 依存関係のあるタスクはリスト構造で保存することにし、依存関係のあるタスクの集まりを「リスト」と呼ぶ。 タスクのグループ化 タスクがグループ化出来るようにグループも作る。 タスクの挿入と追加 リストへの挿入、追加機能を作成する。また、入力フォームも動的フォームである必要がある。 認証機能 laravelの機能を使ったクッキーベースの認証を行う。認証情報自体はAPIで取得する。 データベース設計 ER-図など書こうと思ったのですが、思ったより時間かかりそうだったのでテキストで説明します。 tasksテーブル id(primary) task_list_id(foreign) task order timestamps task_listsテーブル id(primary) group_id(foreign) user_id(foreign) importance urgency timestamps groupsテーブル id(primary) user_id(foreign) group usersテーブル id(primary) name email email_verified_at password remember_token created_at update_at usersテーブルはlaravelのテンプレートで生成されるものを使用しています。このサービスの基本単位はリストであり、リストに1つ以上のタスクが存在します。挿入などのためにtasksテーブルはorderカラムを持っています。 工夫した点 ・TypeSctiptの恩恵を受けるためanyはほとんど使用しなかった ・コンポーネント志向を意識し、切り出せる部分は切り出して使いまわした ・styled-media-queryで作成した3つのブレイクポイントを使用しレスポンシブ対応にした ・ローディング時用のUIを用意(一部) ・入力フォームにて簡単なバリデーションを実施 ・atomicデザインを使用した分かりやすいディレクトリ構造 ・動的フォームの実装 改善が必要な点 ・再レンダリングへの最適化がいまいち ・Promiseへの理解が足りない ・api処理の切り出しがうまく出来ていない ・結果として同じロジックが書かれている部分がある ・見た目とロジックが分離出来ていない おわりに 想像していた倍時間がかかりましたが、自分が思っている機能の半分くらいは実現できました。タスクの停止機能や、別の表示方法などやりたかったことはいっぱいあったのですが、期限内に終わらせることも大切だなと感じました。まだサービスとしてはバグが多すぎるので、これからどんどん改善していきたいと思います。
- 投稿日:2021-10-26T06:06:53+09:00
Web開発者向けの24のChrome拡張機能
今日の投稿では、ウェブサイトのデザインと開発で一般的に使用されているGoogleChrome拡張機能について学習します。 Google Chromeとは何ですか? Google Chromeは、2008年に製造されたWebブラウザであるGoogleの有名で成功した製品の1つです。これは、高度なセキュリティ機能と優れたブラウジングエクスペリエンスを備えたクロスプラットフォームのWebブラウザです。 さらに、アドレスバーのURL提案、メモリ使用量の最適化、ページ応答時間の短縮など、他の多くのデバイスで一緒に使用できる便利なプロパティがいくつか見つかりました。 それだけでなく、プログラマーが作業効率を高め、時間と労力を節約するのに役立つ拡張機能も提供します。 次に、一般的に使用されるChrome拡張機能をいくつか見てみましょう。 Lorem Ipsum Generator Lorem Ipsum Generatorは、必要な段落と行の数を指定することにより、ドキュメントをすばやく作成するのに役立ちます。 Webページ上にコンポーネントを構築する場合、人々はコンテンツを使用して、Web上でどのように表示されるかをテストまたは確認することがよくあります。 これにより、ワンクリックで偽のコンテンツを作成できます。 Lorem Ipsum Generator Postman Postmanは、サーバーにHTTPリクエストを送信するのに役立つアプリケーションです。 これは、プログラムAPIを実行またはテストするときに役立ち、GET、POST、DELETE、およびPUTリクエストを簡単に作成できます。 さらに、Postmanを使い始めたばかりのときに質問をするのに役立つ、多数のプログラマーがいる専用のフォーラムがあります。 Postman JavaScript and CSS Code Beautifier JavaScriptおよびCSSコードビューティファイアは、CSSおよびJavascriptコードを美化し、読みやすくするのに役立ちます。 通常、ウェブサイトをホスティングにアップロードするときは、可能な限り最適化するために、次の画像のような不要なスペースを削除して、CSSファイルとJavascriptファイルを圧縮することがよくあります ご覧のとおり、コードは一連の文字であるため、読みやすくありません。 したがって、JavaScriptとCSS Code Beautifierを使用して、コードをより科学的かつ簡単に整理する必要があります。 詳細については、下の画像を参照してください。 JavaScript and CSS Code Beautifier Web Developer Web Developerは、100万人以上のユーザーによってインストールされた数少ないものの1つです。 これは、Web開発者がWebページを迅速に開発およびデバッグするのに役立ちます。 これは、無効化、Cookie、CSS、フォーム、画像などのさまざまなツールのコレクションです。 Web Developer Window Resizer Window Resizerは、電話、タブレット、ラップトップ、デスクトップなどのブラウザーでWebサイトの可視性をすばやく構築またはテストするのに役立つ重要なツールです。 ブラウザウィンドウの幅と高さを設定することで、表示サイズを動的に調整することもできます。 Window Resizer Colorzilla Colorzillaを使用すると、Webページ上の任意のオブジェクトの色の値を読み取ることができます。 さらに、クリップボードへの色の自動コピー、最近選択した色の履歴の表示、高度なカラーピッカーなど、その他の便利な機能もサポートしています。 Colorzilla WhatFont WhatFontを使用すると、Webページ要素が使用しているフォントを簡単に識別できます。 フォント名を表示するには、表示するオブジェクトにマウスをインストールして移動するだけです。 WhatFont WhatRuns WhatRunsユーティリティは、フレームワーク、分析ツール、Wordpressプラグイン、フォントなど、Webサイトで使用されているWebテクノロジを識別するのに役立ちます。 必要なページにアクセスし、whatrunsアイコンをクリックするだけで、完全な情報が表示されます。 1分未満。 監視対象サイトが新しいテクノロジーを追加したときに通知を受け取るようにサインアップすることもできます。 WhatRuns CSSViewer CSSViewerを使用すると、色、フォント、サイズ、位置など、最も一般的な方法でWebオブジェクトのCSSプロパティを表示できます。 それを選択して、目的のオブジェクトにカーソルを合わせるだけです。 CSS情報が自動的に表示されます。 CSSViewer Page Ruler Redux Page Ruler Reduxは、ウェブサイトユニットのサイズをピクセル単位で取得するのに役立ちます。 Webページ上の特定の要素の正確なサイズを取得する必要がある場合のWebデザイナーに適しています Page Ruler Redux TinEye Reverse Image Search TinEye逆画像検索は、画像認識技術を使用して、異なる解像度の画像を含む複数のリンクの結果を含むWeb上の画像のサイズ変更、編集、または検索を支援します。 検索する画像を右クリックし、[TinEyeで画像を検索]を選択して、結果が表示されるのを待ちます。 そして、これが私が画像を検索したときの結果です: TinEye Reverse Image Search The Great Suspender Google Chromeを使用するときにご存知のように、RAMの使用は、コンピューターを高速化する上で重要な要素です。 Great Suspenderを使用すると、未使用のタブを一時停止して、ブラウザをよりスムーズに実行できます。 20秒、1分、5分など、タブを使用していないときにタブを一時停止することもできます。 The Great Suspender Marmoset Marmosetは、プログラム内のコードを画像として保存するのに役立ちます。 これは、たとえば、関数のコードをソーシャルネットワーキングサイトのプログラムに入れて共有する必要がある場合に役立ちます。 また、色、言語、テーマの調整などの追加機能を提供して、コードのビジュアルをより人目を引くように見せることもできます。 Marmoset User-Agent Switcher User-Agent Switcherを使用すると、Opera、Safari、Firefox、Internet ExplorerブラウザなどでWebページを表示する方法など、追加のプログラムをインストールしなくても、さまざまな画面やデバイスでWebページを表示できます。 User-Agent Switcher Clear Cache Clear Cacheは、ワンクリックでキャッシュをクリアし、データを閲覧する役割を果たします。 さらに、オプションで、アプリケーションキャッシュ、Cookie、履歴、データベースなど、クリアするデータを選択できます。 Clear Cache React Developer Tools React Developer Toolsは、Chromeの開発者ツールに追加されたReactデバッグツールです。 これにより、Webサイトの開発中にReactコンポーネントを簡単かつ迅速にテストできます。 React Developer Tools Check My Links [マイリンクを確認]を使用すると、ワンクリックでWebサイトの壊れたリンクを確認できます。 Check My Links Checkbot Checkbotは、サイトマップ、404ページ、コンテンツ計画などのさまざまなタイプの要素を使用して、Webサイトの速度、セキュリティ、およびSEOをテストするのに役立ちます。 Checkbot Site Palette SitePaletteツールを使用すると、ブラウザの複数のWebページのカラーパレットをすばやく簡単かつ自動的にエクスポートできます。 Site Palette Web Developer Checklist Web Developer Checklist あなたのウェブサイトが持っていなければならないすべての必需品をチェックするのを助けます。 Web Developer Checklist EditThisCookie EditThisCookieは、WebサイトでのCookieの追加、削除、編集、使用、検索、保護、およびブロックを支援することを目的としたCookieマネージャーです。 EditThisCookie リラックスするのに役立つユーティリティ ここでは、リラックスして生産的な1日を始めるためのエネルギーを増やすためのヒントをいくつか紹介します。 Momentum Tab Flickr Earth View from Google Earth 概要: これを通じて、この記事がGoogleChrome拡張機能を提供してくれることを願っています Web開発で使用できます。ご不明な点がございましたら、メールを送信してください。できるだけ早く回答いたします。 体。 今後ともよろしくお願いいたしますので、よろしくお願いいたします。 あなたが持っていることを望みます 良い一日を! 参照リンクen.niemvuilaptrinh.com
- 投稿日:2021-10-26T02:34:07+09:00
Azure Functions と LINE Notify の組み合わせ(Node.js を利用、ポータルで開発)
この記事は、Azure Functions に HTTPリクエストを送ると、LINEアプリに通知が来る(LINE Notify を利用)という仕組みを軽く試したものです。 Azure Functions周りの開発や設定は、Azure のポータル上で行いました。 手順の概要 今回の手順は、おおまかには以下のとおりです。 LINE Notify のトークンを取得 Azure のポータル上で Azure Functions を使えるようにする Azure Functions でのコーディング前の準備 axios をインストール 環境変数を設定 Azure Functions でのコーディング 実際に進めていく LINE Notify のトークンを取得 LINEアプリへの通知を簡単化するため、LINE Notify を利用します。 ググったりすると情報が出てくると思いますので、手順の詳細は割愛しますが、おおまかには以下のような流れです。 まず、LINE Notify のページにログインをして、画面右上のメニューから「マイページ」へ移動します。 そこで、「アクセストークンの発行(開発者向け)」という部分があるので、「トークンを発行する」と書かれたボタンを押します。 その後のトークンの発行画面では、トークンの名前(何か自分が分かりやすいもの)と、LINEアプリ上で通知を送る先となるトークルームを指定します。 上記の設定を行って、「発行する」ボタンを押すと、以下のトークンが表示される画面が出てきます。 以下の画面で表示されるトークンは、再表示ができないため、ここで必ずコピーしてメモなどしておいてください。 Azure Functions 関連 サンプルを動かす まずは、以下の公式ドキュメントの手順の「関数をテストする」の部分まで進めてください。 ●Azure Portal で初めての関数を作成する | Microsoft Docs https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-function-app-portal サンプルは、以下のような内容になるかと思います。 module.exports = async function (context, req) { context.log('JavaScript HTTP trigger function processed a request.'); const name = (req.query.name || (req.body && req.body.name)); const responseMessage = name ? "Hello, " + name + ". This HTTP triggered function executed successfully." : "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."; context.res = { // status: 200, /* Defaults to 200 */ body: responseMessage }; } プログラムを書いた後、ブラウザなどから HTTPリクエストを送り、意図した通りのレスポンスが返ってくれば OK です。 axios を使えるようにする この後、LINE Notify を使った通知の処理で、axios を利用していきます。 Azure Functions で axios を使えるようにするために、パッケージのインストールを行います。 今回は、ポータル上でそれを進めます。 ポータルのメニューで「開発ツール」 > 「コンソール」と進み、以下のような画面を開きます。 あとは以下の記事にもあるように、上記の画像の右側の部分で npm init や npm install を行っていき、axios をインストールします。 ●Azure Functions に npm install で Node モジュールを追加する|まくろぐ https://maku.blog/p/9t7hs4e/ 環境変数を追加する 上の手順で発行した LINE Notify のトークンを、プログラムの中に直書きするのではなく、環境変数として設定して利用する形にしていきます。 そのために、ポータル上で環境変数の追加を行います。 ポータルのメニューで「設定」 > 「構成」と進み、「アプリケーション設定」の中の「新しいアプリケーション設定」を押します。 そうすると、以下の画面が出てくるので、名前と値をそれぞれ設定しましょう。 自分は、以下のようにしました。 名前: LINE_NOTIFY_TOKEN 値: 【LINE Notify のトークン】 プログラムに手を加える あとは、LINE Notify と連携する処理を加えたプログラムを作成します。 上で試したサンプルを元に、axios で POST する処理を加えたりしました。 LINE Notify のトークンは、上で環境変数に追加していたので、そこから読み込みます。 module.exports = async function (context, req) { context.log('JavaScript HTTP trigger function processed a request.'); const name = (req.query.name || (req.body && req.body.name)); const responseMessage = name ? "Hello, " + name + ". This HTTP triggered function executed successfully." : "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."; context.res = { body: responseMessage }; const axios = require('axios'); const querystring = require('querystring'); const messageLineNotify = name ?`Hello! ${name} from Azure` :`Hello! from Azure`; const res = await axios({ method: 'post', url: 'https://notify-api.line.me/api/notify', headers: { 'Authorization': 'Bearer ' + process.env["LINE_NOTIFY_TOKEN"], 'Content-Type': 'application/x-www-form-urlencoded', }, data: querystring.stringify({ message: messageLineNotify, }), }); context.log(res.data) } あとは、動作確認を行うだけです。 動作確認 以下のように、HTTPリクエストをトリガーにして、LINE Notify を使った LINEアプリへの通知ができました。 元の仕組みの中で、URL の末尾に「クエリ文字列の値 ?name=【文字列】 」があった場合、その文字列がレスポンスに使われるという部分がありました。 LINEアプリへの通知の処理でも、この文字列の有無によって、通知の文章を少し変えるようなことをやっています。 おわりに 環境変数を設定したり、axios による POST の処理を使うような形で、Azure Functions と LINE Notify の組み合わせを試すことができました。 今回、シンプルな内容で試しましたが、さらに別のアプリやサービスとの連携なども加えたりできればと思います。
- 投稿日:2021-10-26T01:18:30+09:00
javascript演習 6,7日目/30日
覚えたこと someとevery const isAdult = people.some(person => new Date()).getFullYear() - person.year >= 19) const allAdult = people.every(person => new Date()).getFullYear() - person.year >= 19) findとfindInex findIndexとslice const index = comments.findIndex(item => { return item.id === 823423 }) //comments.splice(index,1);これでもいい const newComments = [ ...comments.slice(0,index), ...comments.slice(index +1 ) ]; canvas const canvas = document.querySelector('#draw'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx.strokeStyle = '#bada55'; ctx.lineJoin = 'round'; ctx.lineCap = 'round'; マウスで描写 let isDrawing = false; function draw(e) { if(!isDrawing) return; console.log(e) } canvas.addEventListener('mousemove', draw); canvas.addEventListener('mousedown', () => isDrawing = true); canvas.addEventListener('mouseup', () => isDrawing = false); canvas.addEventListener('mouseout', () => isDrawing = false); ーーーーーーーーーーーーーーーーーーーーーーーー 参考
- 投稿日:2021-10-26T00:14:34+09:00
styled-componentsで入力補完を効かせる方法(vscode)
Qiita初投稿です。 テスト投稿も兼ねて。 結論: 拡張機能 「vscode-styled-components」 をインストールする。 こちらの方法がおそらく一番手っ取り早いです。