20220125のJavaScriptに関する記事は18件です。

N予備プログラミング 〜冬コンテスト作品制作過程を晒してみる③〜

みなさんこんばんわ せまる〜♪ショッカー!(締切!)という事で、どんどん実装していきます。 ”18.【サービス開発3】データモデルの実装とユーザーの保存”を写経でGO!! しかーし!今回はDB設計なので慎重に行くとこ! データベース作成と定義を自前のやつにさしかえて作りますよと。うーさすがに緊張! データベース名とデータ置き場(ボリューム先)名両方しっかり確認してyml書き直しーの! docker-compose exec db bash でデータベース用コンテナ開きーの! psqlコマンドでデータベース作成!!渾身のポチっとな!!! いったー!データベース作成でドキドキしすぎた。ふう〜。 このあとデータモデル実装も大事なとこだけど、MPが尽きたから今日はこのへんで! (それにしても4−18長いなー。めちゃ実装量あるじゃん。。うーん鬼畜回の悪寒!!)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[JS](基礎)関数について

アウトプットとして Rubyでいうところのメソッドを、JavaScriptでは関数と呼びます。 この関数ですが、いろんな記述の方法があるので整理するために記事にしたいと思いました。 いろいろな関数定義 関数宣言(function) JavaScriptではfunction 関数名(){ 処理 }と記述することで関数を定義することができます。 function 関数名(引数) { // 処理 } 例 function calc(num1,num2){ return num1*num2 } const num1 = 3 const num2 = 4 console.log(calc(num1,num2)) // => 12 無名関数 無名関数は、関数名なしで関数を定義することができます。より簡潔なコードが記述できるという点がメリット。 const hello = function(){ // 処理 } 例 const calc = function(num1,num2){ return num1*num2 } const num1 = 3 const num2 = 4 console.log(calc(num1,num2)) // => 12 即時関数 関数を定義すると同時に実行される構文。関数を定義してから呼び出すという手間を省くことができます。 (function 関数名(引数) { // 処理 })(呼び出すための引数) 例 (function countNum(num) { console.log(num) })(1) // => 1 ()の中にfunctionからはじまる関数定義そのものを配置することで、その関数を即実行するということができるようになります。 アロー関数 functionの記述を省略し、その代わりに()=>という記述によって関数を定義する構文です。より短い記述で関数定義をできるという点がメリット。 // 無名関数 const 変数名 = function(){ 処理 } // アロー関数 const 変数名 = () => { 処理 } 例 const countNum = (num) => { console.log(num) } countNum(1) // => 1 それぞれの関数の特徴まとめ 関数定義の種類 特徴 関数宣言 標準的な関数の定義 無名関数 関数を多く使用するコードであるときに使用する。関数名の重複を避けることができる。 即時関数 流用する可能性のない関数を定義するときに使用する。別途関数を定義する手間がない。 アロー関数 無名関数または即時関数において、より省略した記述をしたい時に使用する。 JavaScriptの関数における戻り値 JavaScriptでは関数の戻り値をreturnを用いて明示する必要があります。 returnを記述していない例 function calc(num1, num2){ num1 * num2 } num1 = 3 num2 = 5 console.log(calc(num1, num2)) // => undefined(戻り値が取得できてない) returnを記述した例 function calc(num1, num2){ return num1 * num2 //戻り値を得るためにreturnを記述 } num1 = 3 num2 = 5 console.log(calc(num1, num2)) // => 15 まとめ 関数名などは覚える必要はないと思いますが、どういう書き方があってどういう特徴があるのかは覚えておきたいです! ※補足等ありましたらコメントいただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxt.jsにGraphQLやRESTをモックする仕組みを導入する

どうも。最近はフロントエンド側のタスクが多くなったふじむーです。 仕事にて、バックエンド側ができるまでの間GraphQLサーバーをモックする仕組みを作ることになりました。 その実装の中での気づきや導入手順などをまとめていこうと思います。 GraphQLはなんぞやについては、今回割愛してます。 初のGraphQLのモック構築で、まだまだ発展途上です。 もし異なる点などありましたら、アドバイスいただけると幸いです! 環境 Nuxt.js(2系) / TypeScript Apollo Client(GraphQLを使用するためのライブラリ) 結論 MockServiceWorker(以下MSW)を使用することにしました。 https://mswjs.io/docs/ MSWは別途ポートを開けてサーバーを立てる必要もなく、 定義したモックファイルをimportしていけばモックできるので非常に手軽でした。 モックで返す値を設定したり、返却する時間を遅らせたりと、いろいろできそうでした。 公式のチュートリアルに沿っていけば導入はできそうです。 が、Nuxt用ににちょっと設定する必要はありました。 (Nuxt.jsだけチョット省かれてた...) MSWとは MSWとは、モックサーバーっぽいことをしてくれるライブラリです。 実際のリクエストをネットワークレベルで監視してくれて、該当するリクエストが来たら 定義されたデータを返します。 ライブラリなので、特にポートを開けてサーバーを立てるわけでもなく、手軽に導入できました。 MSWは、モックで返すデータや設定もいろいろ調整が可能です。 例えばこんなことができます。 返却するデータを任意に設定できる レスポンスするタイミングを遅らせる(ロード中の動作を確認できる) HTTPステータスを任意のものにできる エラーメッセージを任意のものに設定できる また、console上でちゃんとモックできているかも確認できるので非常に便利です。 導入した理由 開発を進めるにあたって、バックエンド側はまだ未完成ですが、 フロントの開発を進める必要がありました。 そこで、フロント側としてどういうモックが求められるかを考慮し下記のように設定しました。 一覧画面のページネーションなどの確認のため、返却するデータ数を調整できるようにする あくまで補佐であり、モックを作ることに時間をかけすぎないようにする そこから選定に入りました。 Apollo ServerとMSWで悩みましたが、 下記の特徴から、今回はMSWを導入することにしました。 既存のリポジトリ内でモックファイルを定義することができる 正常系、異常系に合わせて返却するデータを自由に設定できる 定義したモックは、MSWで指定された配列に入れるだけでモックできる リクエストをネットワークレベルで監視してくれるため、より本番環境に近い状態でモックできたりstorybookなどでも使えるようで拡張性がよさそう MSWを導入 アーキテクチャ 公式に沿ってmocksというフォルダを作成し、そこにまとめています。 mocks handlers queries // queryのリゾルバを定義したファイル mutations // mutationのリゾルバを定義したファイル handlers.ts // handlersで定義されたリゾルバをインポートしモックするファイル browser.ts static mockServiceWorker.js 導入手順 公式ドキュメントに沿っていくと、わりとすんなり進められますが、 Nuxt.jsように設定する箇所がいくつかあったので合わせて記載していきます。 (ほとんど公式の抜粋です。) 今回はgraphqlでgetCarsというqueryをモックするとします。 1、まずはインストール 何はともあれインストールです。 $ npm install msw --save-dev # or $ yarn add msw --dev 2、mocksフォルダを作成します mocksのフォルダを作成します。 そして、mocks内にhandlers.tsを作成します。 このhandlers.tsに、MSWでモックするqueryやmutationを定義していきます。 3、モックする内容を定義する 公式では handlers.tsのhandlers内に直接書いていますが、開発を進めるうちに記述量が膨大になりそうなので、handlersというフォルダを作成し、そこに書いていくことにしました。 モックでは下記を書きます。 モックするクエリー名 レスポンスの設定 書いたファイルはこんな感じです。 import { graphql } from 'msw' /** * リゾルバの定義 * @returns モックで返却する値や設定 */ export const getCarsHandler = graphql.query<getCarsQuery>('getCars', (req, res, ctx) => { return res( ctx.data({ cars: [{ __typename: 'getCars', id: 1, name: 'R35 GT-R', maker: '日産', }], }), ) }) .queryの第一引数でモックするクエリー名を定義します。 これをもとにモックするかしないかをMSWが判断します。 第二引数では、レスポンスの設定です。 上記の状態で、carsのオブジェクトを返却します。 レスポンスの設定ではreq, res, ctxの引数があります。 req リクエストに関する情報が入っている res モック応答を作成する関数 ctx 現在のリクエストハンドラに固有の それぞれの中身については下記ドキュメントから見られます。 https://mswjs.io/docs/basics/response-resolver 少し余談ですが、 返却するデータを任意にしたかったり、ロード中の動作も見たかったので下記のようにしてみました。 /** * モックの返却値 * @returns {Object} getCarsで返却する値 * @returns {String} __typename query名 * @returns {Number} id 車のid * @returns {String} name 車名 * @returns {String} maker メーカー */ const mockData = (): Cars => ({ __typename: 'getCars', id: 1, name: 'R35 GT-R', maker: '日産', }) /** * 返却するデータ数 */ const length = 100 /** * リゾルバの定義 */ export const getCarsHandler = graphql.query<getCarsQuery>('getCars', (req, res, ctx) => { return res( ctx.data({ cars: Array.from({ length: length }, mockData), }), // 2000ミリ秒遅らせてレスポンスする。(ロード中の動作などを確認できる。省略可) ctx.delay(2000) ) }) Array.fromで配列の長さと要素を指定できるので、それを使って返却するデータを変えられるようにしてみました。 ただ、これは同じ要素が指定した数になるので、それぞれ要素の値をバラバラにしたかったらFaker.jsなどを使うのが良いかもしれないです。 他にもレスポンスで使用できるプロパティがあります。 下記ドキュメントを参考していただけると幸いです。 https://mswjs.io/docs/api/response 3、2で定義したモックをhandlers.tsにインポートします。 import { getCarsHandler } from '略' /** * MSWでモックするQuery、Mutationを定義するファイル * 下記配列に含まれたハンドラがモックされる。 */ export const handlers = [ getCarsHandler, ] 4、mockServiceWorker.jsを自動生成します 公式では パブリックディレクトリーを対象に生成するとあります。 が、なぜかNuxt.jsのパブリックディレクトリには触れられておらず、、、 ということで調べてみることに。 翻訳してみると通常、サーバーのルートディレクトリですとのことでした。 Nuxtの公式を見てみると、どうやらstaticディレクトリがそれのようです。 https://nuxtjs.org/docs/directory-structure/static ということで、staticディレクトリに作成します。 mockServiceWorker.jsはコマンドを打つと自動生成されます。 npx msw init static / --save 実行すると、mockServiceWorker.jsが自動生成され、 package.jsonに追記されます。 "msw": { "workerDirectory": "static" } 拡張子が.jsですが、自動生成されたファイルを見てみるとこのファイルは編集しないでくださいとコメントがあるので、なにも触れないことにしました。 /** * Mock Service Worker (0.36.3). * @see https://github.com/mswjs/msw * - Please do NOT modify this file. * - Please do NOT serve this file on production. */ 5、プラグインにして、MSWを動作させる 開発環境のみで動作させます。 import { worker } from '略' /** * MSWを起動させる定義ファイル */ export default () => { if (process.env.NODE_ENV === 'development') { worker.start() } } 導入してみた感想 まだ導入数日なので、参考になるかわかりませんが、、 結構手軽にモックできてよい! 初期の構築が終われば、その後はモックの定義とhandlers.tsへの定義で済むので手軽です。 (モックの定義もコピーすればほぼよいので、返す内容の定義とhandlersへの定義などで済む) モックで定義していないクエリーに関しては、実際に設定したエンドポイントに見に行ってくれるので 結構長く使えそうな感じはしています。 参考 MSW 導入 Nuxt公式 Mock Service Worker(msw)をNuxt.jsでモックサーバーとして使ってみる Type-safe API mocking with Mock Service Worker and TypeScript Array.from()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

yarnのインストール(Windows)

はじめに  以前、自分が使っている古い方のPCで、Reactを使おうと思ってyarnをインストールしたのですが、パスが通っていないのかコマンドが認識されず、yarnが実行できない。  思い切って新しいPC(Surface Pro8)の方でもう一度インストールしてみようと思って、再度挑戦しました。  ちなみにyarnとは、Facebook社(現メタ社)によって開発された、npmよりも処理が早いJavaScriptのパッケージ管理システムです。よくnpmの上位互換として紹介されているので、流行に乗って使えたほうが良いかなと奮闘中です。ReactもFacebookによる開発ですよね。Facebookはこの辺りの事情に精通しているのでしょうか。 作業環境 PC: SurfacePro8 OS: Windows11 使用ターミナル: コマンドプロンプト その他必要環境: node.js、npm 手順  何はともあれ、まずは公式ドキュメント!ということで、yarnpkg.comのGETTING STARTED → Installationの手順を試してみることに。  最初に、「yarnを使うのは、Corepackを通して扱うのが良い」という趣旨のことが書いてあるので、素直にCorepackを使おうと $corepack enable と実行すると、  そのコマンドは許可されていません、と出ます。node.jsフォルダの中のnpmファイルを見るように指示があるものの、見てもよく分からない...。エラーメッセージを元にあれこれ調べてみたものの、明確な解決策は見つかりませんでした。  「要するに管理者じゃないからダメなんでしょ?ええい、管理者でゴリ押してしまえ」と半ばヤケクソになって「管理者権限 コマンドプロンプト」と検索。どうやらコマンドプロンプトのアプリアイコンを右クリックすれば管理者権限で入れるみたいなので、管理者権限として入った後、再度実行。  ......できました。あまりにもあっけないです。必要なのは、管理者権限で実行してよいのかという不安に打ち勝つ勇気のみですね。  あとは、公式ドキュメントの手順に沿って、npm i -g corepack、 yarn init -2 というコマンドを順に実行するだけです。何やら不穏なエラーメッセージが出ていてこの先が不安ですが、とりあえず良しとしましょう。ん?できてない?一応実行したディレクトリ下に「.yarn」というディレクトリと、package.jsonができているので、できているということにしましょう。またこの辺りで問題が起こったら、記事にするかもしれません。 総論  とりあえず何をするにも、公式ドキュメントのGETTING STARTEDが正義です。このような環境構築系は特に、公式ドキュメントや、エラーメッセージ内ででてきたリンクを参考にするのが一番手っ取り早いと思いました。 参考 公式ドキュメント https://yarnpkg.com/getting-started/install 最後のエラー時に参考として出てきた公式ドキュメントのページ。 https://classic.yarnpkg.com/en/docs/cli/init yarn initで何が行われ、どのようにyarnを初期化しているかについては分かりやすく載っているものの、今回のエラーの原因は突き止められませんでした。 Corepackについて https://nodejs.org/dist/latest/docs/api/corepack.html 管理者権限でコマンドプロンプトに入る方法 https://solutions.vaio.com/2663
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【アコーディオン】jQueryのslideToggleを生jsで再現してみた。Vue.jsやReactでも使用可

jQueryのslideToggleは数行で実装できるので便利でした。 今回、数行とはいきませんがそれなりにシンプルなコードでslideToggleの動きを再現してみました。 生jsの場合 See the Pen accrodion without jQuery by monji (@monji88) on CodePen. e.targetとnextElementSiblingを使用しています。 e.targetについてはこちらの記事にも書かせて頂いてます。 https://qiita.com/monji586/items/711bc6d78c41cf02c752 Vue.jsの場合 See the Pen Untitled by monji (@monji88) on CodePen. Vueなのでtransitionタグなど使おうかとも思いましたが、 普通に生jsのコードを使いまわしたほうがシンプルでした。 el:"#app"とかはVue2の書き方ですがmethodsの部分はVue3でもそのまま使えると思います。 Reactの場合 すみませんReactは触ったことないのでコードを用意してません。 でも生jsのコードを転用してもらえれば動くと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

読みやすいコード入門編(javascript)

無駄にライブラリを使わない 標準機能で実現できることにライブラリを使わないことを心がける。 マジックナンバーには名前をつける // この「100」は何? const pages = Math.ceil(records.length / 100); // ああ、1ページあたり100件ってことね! const maxRecordsPerPage = 100; const pages = Math.ceil(records.length / maxRecordsPerPage); 識別子を短くしない // この変数はどういうこと? const cx = 5; const cy = 10; // 意味がはっきりした! const centerX = 5; const centerY = 10; // 関数名から機能を把握しにくい! function fetchTrk(id) { return fetch('./api/tracking/' + id); } // これなら多少わかりやすい function fetchPersonTrackingData(personId) { return fetch('./api/tracking/' + personId); } デフォルト引数はオブジェクトにする // 複数のデフォルト引数を使っている function findBookRecords(queryString, useCache = true, maxRecords = 50, caseSensitive = false) { // 取得処理 } // どの引数が何を意味しているのかわかりにくい const bookRecords = findBookRecords('JavaScript', true, 10, true); // デフォルト引数をオブジェクトにしている function findBookRecords(queryString, options = {}) { // 取得処理 } // 引数の意味がわかりやすく、順番にも左右されない const bookRecords = findBookRecords('JavaScript', { useCache: true, maxRecords: 10, caseSensitive: true }); イベントハンドラー関数は「on」で始めること イベントをキャッチしたら始まる処理、もしくはイベントをキャッチするグローブのこと 垂直のインデント: コードを論理ブロックに分割するための空行 function pow(x, n) { let result = 1; // <-- for (let i = 0; i < n; i++) { result *= x; } // <-- return result; } ネストレベル 下のコードの方が見やすい function pow(x, n) { if (n < 0) { alert("エラー"); } else { let result = 1; for (let i = 0; i < n; i++) { result *= x; } return result; } } function pow(x, n) { if (n < 0) { alert("エラー"); return; } let result = 1; for (let i = 0; i < n; i++) { result *= x; } return result; } 関数の配置 NG:ヘルパー関数を使うコードの上に関数を記述する // 関数宣言 function createElement() { ... } function setHandler(elem) { ... } function walkAround() { ... } // 関数を使用するコード let elem = createElement(); setHandler(elem); walkAround(); OK:コードが最初で、その後に関数を記述 // 関数を使用するコード let elem = createElement(); setHandler(elem); walkAround(); // --- ヘルパー関数 --- function createElement() { ... } function setHandler(elem) { ... } function walkAround() { ... } その他心構え シンプルなコードは、「素人っぽく」見えることもある プログラミングにおける1つ1つの判断は「そのコードが変更される」前提で行う。 コードは1つずつタスクを行うようにしなければいけない。そのタスクは小さくなるように分割する。 コードをたくさんの小さい部分に分割する(関数などが長くなったら分割して短くする)。 プログラミングにおいては「今日単純なことをして、明日変更が必要になった時に、変更のコストを支払う」方が「今日複雑なことをして、結局使わない」よりも良い結果を生む。 問題を声に出して説明するだけで、解決策が見つかることがある。(通称ラバーダッキング) 関数を使う側にとって必要なのは、その関数が「何をするか(What)」であって、「どうやってするか(How)」ではありません。言い換えると、内部実装の情報まで関数名に含める必要はありません。 https://sbfl.net/blog/2018/03/24/readable-javascript-code/ https://note.com/shiory602/n/n5d15cdd28823 https://ja.javascript.info/coding-style https://engineeeer.com/readable-code-tips/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

要素の抽出・削除・書き換えなどの配列操作(JavaScript)

配列から重複した値を削除する const fruits = ["banana", "apple", "apple", "orange", "grape", "apple"]; // fromを使う方法 const uniqueFruits = Array.from(new Set(fruits)); console.log(uniqueFruits) // ...を使う方法 const uniqueFruits2 = [...new Set(fruits)]; console.log(uniqueFruits2) // 共に ["banana", "apple", "orange", "grape"] // 従来の方法(おすすめしない) const result = fruits.filter((x, i, self) => { return self.indexOf(x) === i; }); console.log(result); Array.from詳細 new Set詳細 配列の中で特定のkey:valueだけを取得する const friends = [ { name: 'John', age: 22 }, { name: 'Peter', age: 23 }, { name: 'Mark', age: 24 }, { name: 'Maria', age: 22 }, { name: 'Monica', age: 21 }, { name: 'Martha', age: 19 }, ] const friendsNames = Array.from(friends, ({name}) => name); console.log(friendsNames); // 従来の方法(おすすめしない) const friendsNames = friends.map((friend) => { return friend.name }) console.log(friendsNames); 配列で何らかのデータで埋めたい場合 const array1 = [1, 2, 3, 4]; // 配列のindex2~4を0で埋める console.log(array1.fill(0, 2, 4)); // [1, 2, 0, 0] // 配列のindex2以降を0で埋める console.log(array1.fill(5, 2)); // [1, 2, 5, 5] // 配列の全てを6で埋める console.log(array1.fill(6)); // [6, 6, 6, 6] 2つの配列から共通項を抽出する const numOne = [0, 2, 4, 6, 8, 8]; const numTwo = [1, 2, 3, 4, 5, 6]; const duplicatedValues = [...new Set(numOne)].filter(item => numTwo.includes(item)); console.log(duplicatedValues); // [2, 4, 6] 配列の中からfalsyな値を取り除く const mixedArr = [0, "blue", "", NaN, 9, true, undefined, "white", false]; const trueArr = mixedArr.filter(Boolean); console.log(trueArr); // returns ["blue", 9, true, "white"] 配列の中の数字を全て足す const nums = [1, 5, 2, 6]; const sum = nums.reduce((x, y) => x + y); console.log(sum); // 14 配列を1つのオブジェクトにする const data = [ { name: 'Taro', age: 20 }, { name: 'Hanako', age: 25 }, { name: 'Tom', age: 30 } ]; const result = data.reduce((prev, current) => { prev[current.name] = current.age; return prev; }, {}); console.log(result); // {Taro: 20, Hanako: 25, Tom: 30} 配列を1つのindex{key:value}のオブジェクトにする const data = [ { name: 'Taro', age: 20 }, { name: 'Hanako', age: 25 }, { name: 'Tom', age: 30 } ]; const result = data.reduce((prev, current, index) => ({ ...prev, [index]: current}), {}); console.log(result) /* { 0: { age: 20, name: "Taro" }, 1: { age: 25, name: "Hanako" }, 2: { age: 30, name: "Tom" } } */ 配列の中で特定のkey:valueだけを取得する const data = [ { id: 1, name: 'Taro', age: 20, country: 'Japan'}, { id: 2, name: 'Yan', age: 30, country: 'China'}, { id: 3, name: 'Bob', age: 40, country: 'America'}, ]; const result = data.reduce((prev, current) => { const { name, country } = current; prev.push({ name, country }); return prev; }, []); const result2 = data.map((data) => { return { name: data.name, country: data.country, } }) console.log(result); console.log(result2); /* 共に [{ country: "Japan", name: "Taro" }, { country: "China", name: "Yan" }, { country: "America", name: "Bob" }] */ 配列の中で条件にあったものだけを抽出する const accounts = [ { id: 1, firstName: 'taro', lastName: 'sato', age: 10, sex: 'male' }, { id: 2, firstName: 'jiro', lastName: 'suzuki', age: 28, sex: 'male' }, { id: 3, firstName: 'saburo', lastName: 'takahashi', age: 19, sex: 'male' }, { id: 4, firstName: 'hanako', lastName: 'tanaka', age: 10, sex: 'female' }, { id: 5, firstName: 'sachiko', lastName: 'kobayashi', age: 20, sex: 'female' } ]; // accounts をもとにして、未成年男性のフルネームを配列で取得したい // 期待する結果 ["taro sato", "saburo takahashi"] const result= accounts.filter(data => data.age < 20 && data.sex === 'male') .map(data => `${data.firstName} ${data.lastName}`); console.log(result) 参考記事 https://qiita.com/rana_kualu/items/24e5b6009ad831102db4 https://kde.hateblo.jp/entry/2018/10/13/065738#配列をオブジェクトにする https://chaika.hatenablog.com/entry/2019/05/07/083000 https://ics.media/entry/200825/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptのコンストラクタとプロトタイプの違いについて

コンストラクタ function Dog(name, cry) { this.name = name; this.bark = function() { console.log(cry); }; } var dog = new Dog('きなこ', 'わんわん'); console.log(dog.name); // きなこ dog.bark(); // わんわん 上記のコードでnewを取り除くとエラーが発生する。この違いは何か?実は暗黙のルールで二行加わっています。 function Dog(name, cry) { // var this = {}; this.name = name; this.bark = function() { console.log(cry); }; // return this; } newをつけない場合はself等を用意しなくてはならない function Dog(name, cry) { var self = {}; self.name = name; self.bark = function() { console.log(cry); }; return self; } var dog = Dog('きなこ', 'わんわん'); console.log(dog.name); // きなこ dog.bark(); // わんわん プロトタイプ プロトタイプとは「オブジェクト」のことであり、親の能力は子にも受け継がれている的なニュアンス prototypeとは? prototypeプロパティを利用することで、オブジェクトにメソッドやプロパティを定義することが可能にする const Member = function (firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } Member.prototype.getName = function () { return this.firstName + this.lastName; } const mem1 = new Member('田中', '太郎'); const mem2 = new Member('山田', '二郎'); console.log(mem1.getName()); console.log(mem2.getName()); 上と下では表示結果は同じ function Dog() {} Dog.prototype.bark = function() { console.log('わんわん'); }; var dog = new Dog(); dog.bark(); //'わんわん'; ------------------------ function Dog() { this.bark = function() { console.log('わんわん'); }; } var dog = new Dog(); dog.bark(); //'わんわん'; しかし、下はnewはこんな暗黙のルールで余計な記述が作られる。そのため毎回空オブジェクトを作成し、毎回新しくbark関数を定義している function Dog() { // var this = {}; this.bark = function() { console.log('わんわん'); }; // return this; } 2つ以上インスタンスを作る時はプロトタイプの出番 function Dog(cry) { this.cry = cry; } Dog.prototype.bark = function() { console.log(this.cry); }; const chiwawa = new Dog('きゃんきゃん'); chiwawa.bark(); //'きゃんきゃん'; const shiba = new Dog('わんわん'); shiba.bark(); //'わんわん'; 使わない場合は下記のようなコードになる function Dog(cry) { this.cry = cry; this.bark = function() { console.log(this.cry); }; } const chiwawa = new Dog('きゃんきゃん'); chiwawa.bark(); //'きゃんきゃん'; const shiba = new Dog('わんわん'); shiba.bark(); //'わんわん';
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Agora SDK x Next.js

はじめに Next.jsの人気が高まっているということで、Agora SDKでも動作するかサンプルコードを書いてみました。 Next.jsについての詳しい知見はあまり持っていませんので、お見苦しい書き方があるかもしれませんがご了承ください。 サンプルコード サンプルコードはこちらAgoraIO-NextJSに公開しております。 機能としては、単純に自映像を表示してパブリッシュするだけのものとなっています。 構成 構成はいたってシンプルで、実装はすべてVideoComponents.jsにまとまっています。 実装内容 index.js import dynamic from 'next/dynamic' const DynamicComponent = dynamic(() => import('../components/VideoComponent').then((mod) => mod.VideoComponent), { ssr: false } ) export default function Home() { return ( <div> <DynamicComponent /> </div> ) } index.jsではSSRを無効にする実装をしています。AgoraSDKがWindowオブジェクトを利用している為、 ここでSDKをimportするとwindow is not definedが発生してしまいます。よって、SDKの実装についてはcomponentにまとめています。 (AgoraSDK以外にも依存ライブラリが原因でこのエラーに遭遇する場合もよくありそうです) 公式ドキュメントの解説はこちらにあります。 components/VideoComponent.js import AgoraRTC from "agora-rtc-sdk-ng"; let rtc = { localAudioTrack: null, localVideoTrack: null, client: null }; let options = { appId: YOUR APP ID, channel: "nextjs", token: null, uid: 123456 }; async function join(){ rtc.client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" }); await rtc.client.join(options.appId, options.channel, options.token, options.uid); rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack(); rtc.localVideoTrack = await AgoraRTC.createCameraVideoTrack(); rtc.localVideoTrack.play("local_video"); await rtc.client.publish([rtc.localAudioTrack, rtc.localVideoTrack]); } export function VideoComponent() { return ( <div> <h2>Agora Video Web SDK Quickstart Next.js</h2> <div> <div> <button type="button" id="join" onClick={() => join()} >JOIN</button> </div> <div id="local_video" style={{width: '320px', height: '240px'}}></div> </div> </div> ) } Joinボタンとビデオ表示領域だけ用意したシンプルなHTMLと、カメラマイク取得してパブリッシュするというシンプルな実装になっています。 以下のような実行結果になります。 無事に動作してくれました。 Windowオブジェクトの取り扱いがポイントとなりそうです。 最後に agora.ioに関するお問い合わせはこちらから
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js(javascript)でulid

背景 自分が作業する環境でULIDをJavascript(Vue.js)で使用する機会が出てきたため、調べたところ記事もそんなに出てないし、投稿しようと思いました。 環境 ulidx 0.3.0 vue 2.6.14 実装方法 関連するライブラリをインストール ulidx 今回使用するライブラリはulidxです。npmにはulidというライブラリがあるんですが、長くメンテナンスがされていないようです。そのulidを元にしつつ、機能を拡張させたものがulidxになります。今回はこのulidxの使い方を紹介していきます。  インストール npm install ulidx 使い方 ulidの作成 ulidxをインポートします。以下のコードはulidの作成をしています。 import { ulid } from "ulidx"; createULID(){ let ulidCreated = ulid(); // 01FT83PSC9VD2BB77H1M0K5P2A let ulidSeed = ulid(100); //シードを指定してULIDを作成 //0000000034WMEBWSY2JZC947HD }, 単調増加するulidの作成 monotonicFactoryは単調増加するULIDを作成できます。 import { monotonicFactory } from "ulidx"; monoULID(){ let ulidMono = monotonicFactory(); let ulidM1 = ulidMono(150000); //0000004JFGTT02CT60BNH4SDCR let ulidM2 = ulidMono(150000); //0000004JFGTT02CT60BNH4SDCS let ulidM3 = ulidMono(150000); //0000004JFGTT02CT60BNH4SDCT } ulidからUNIX時間に変換 ULIDをUNIXに変換します。 import { decodeTime } from "ulidx"; decodeULID(){ let Unix = decodeTime("01FT850VYMMNZR7CNMTZZCD90V"); //1643098697684 //UNIXから日本時間に変換 let date = new Date(Unix) console.log(date.toString()) //Tue Jan 25 2022 17:18:17 GMT+0900 (日本標準時) } サンプルコード HelloWorld.vue <template> <div class="hello"> <ul style="margin:0 auto 0 auto; width:600px; text-right"> <li>normal create:{{ulidCreated}}</li> <li>seed create:{{ulidSeed}}</li> <li>mono create1:{{ulidM1}}</li> <li>mono create2:{{ulidM2}}</li> <li>mono create3:{{ulidM3}}</li> <li>decode(UNIX):{{ulidDecoded}}</li> </ul> </div> </template> <script> import { ulid,monotonicFactory,decodeTime } from "ulidx"; export default { name: 'HelloWorld', data: () => ({ ulidCreated:null, ulidDecoded:null, ulidSeed:null, ulidM1:null, ulidM2:null, ulidM3:null }), mounted(){ this.createULID(); this.seedULID(); this.monoULID(); this.decodeULID(); }, methods:{ createULID(){ this.ulidCreated = ulid(); }, seedULID(){ this.ulidSeed = ulid(100); }, monoULID(){ let ulidMono = monotonicFactory(); this.ulidM1 = ulidMono(150000); this.ulidM2 = ulidMono(150000); this.ulidM3 = ulidMono(150000); }, decodeULID(){ this.ulidDecoded = decodeTime("01FT850VYMMNZR7CNMTZZCD90V"); let date = new Date( this.ulidDecoded) console.log(date.toString()) } } } </script> まとめ 今回はVueでのULIDの取り扱い方法について書きました。何かご指摘等あれば、ぜひコメントをください! 参考 ulidxのドキュメントページ JavaScriptでunixtimeから日時へ変換するやり方のメモ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

タイピングゲームを作ろう#1〜環境設定〜

こんにちは! 今回からパート3ぐらいに分けてタイピングゲームを作っていきたいと思います #1→環境設定 #2→プログラム #3→装飾等 このようにやっていこうと思います 環境設定 では、いつもの環境設定からやっていきます まず、HTMLをこのようにしてください index.html <title>タイピングゲーム</title> <meta charset="utf-8"> <canvas id="canvas" style="background-color:#acacac; position:absolute;left:25%;" height="600px" width="600px"></canvas> <script src="index.js"></script> これで、canvasが完成しました 次にjavascriptを作っていきます index.jsというファイルを作成して、こちらでメインループを作成してください index.js //メインループ function main() { setTimeout(main,0); } //初期設定 window.onload=function() { setTimeout(main,0); } では、これで環境設定が終わりました 今回は短いですがこれで終わりたいと思います
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Jamstackセミナー(2/10)開催のお知らせ

今回はBejamas社のブログ記事のご紹介ではなく 無料のJamstack_Webセミナーについてお知らせいたします 2022年2月10日(木)15時00分〜16時00分で Jamstackのデモを見ていただきつつ、 「Webサイト改善」をテーマにお話しさせていただくセミナーを開催したします。 ※本セミナーは、2021年7月6日(火)に開催したWebセミナーと同じ内容です。 詳細はConnpassでの告知をご確認ください https://connpass.com/event/237543/ 最新のWeb開発事情にご興味のある方は、良ければご参加ください
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AngularJS ってどんなもの

はじめに WEB開発をするにあたり、必要とされるのはWEBフレームワークです。 フレームワークなしでもWEB開発は進められますが、フレームワークを利用すると効率よく開発ができるようになります。 フレームワークは便利ですが、WEB開発に対応しているものが多く存在し選ぶのが難しい状況です。 今回はフレームワークの中でもAngularJSについてご調べてみました。 良ければ今後の社内開発ツールのひとつにしようかと思います! AngularJSとは... AngularJSはGoogle社が中心となって開発されたJavaScriptで作られたWEBフレームワークです。 オープンソースのソフトウェアとなっています。 WEBフレームワークらしく、MVCモデルに対応しています。 マスターメンテナンスのようなCRUD系のアプリケーション、業務系アプリケーションのような各機能が独立した画面として存在し、フォーム(form)を使ってデータの送受信を行うようなアプリケーションに向いているといわれています。 メリット/デメリット 【メリット】 ・フルスタックフレームワーク  WEBアプリケーション開発を前提として開発されているため、SPA(Single Page Application)開発に必要な機能が含まれています。  ルーティングやAjax通信、双方向データバインディングなどの機能は簡単な記述で呼び出せるようになっています。   ・開発工数が削減可能  AngularJSは、多機能な割に動かすために必要な工数がそれほど多くありません。  ディレクティブで設定した記述を指定することで、各機能を呼び出すことができます。  AngularJSをうまく使えば開発にスピード感が出ることが期待できます。 【デメリット】 AngularJSにもいくつかのデメリットがあります。 ・パフォーマンスが低い デメリットとして1番気になるのは、パフォーマンスの低さです。 AngularJSには「スコープ」と呼ばれる機能があります。 これは一般にプログラミングで利用されるスコープのことではなく、画面を監視/変更する特殊なオブジェクトを指しています。 AngularJSには「消化サイクル(Digest Cycle)」と呼ばれるある種のループ構造がありむやみにスコープを増やしてしまうと、画面を監視する処理が無駄に呼ばれてしまい速度に影響が出てしまいます。   ・様々な記述方法がある AngularJSでは同一の処理を作るのに複数の記述方法が存在しています。 いろんな記載ができるのはメリットのように感じますが、チーム開発においてはソースコードの統一が図れなくリスクを生みます。 ソースコードの書き方が統一されていないとコードの可読性が下がってしまうので不具合につながりかねません。 AngularJSの主な機能 AngularJSを導入することで簡単に実現できることは以下のようなものがあります。 ①ルーティング機能  モジュールを使用して下記のようにルーティングを定義することができます。 hoge.js ## ルーティング ###################### angular.module('app', ['ngNewRouter']) .controller('AppController', ['$router', AppController]); //ルーティング定義 AppController.$routeConfig([ {path: '/', component: 'home' } ]); //コントローラー定義 function AppController ($router) { …… }   ②Ajax通信機能  JavaScriptで行うサーバとの通信といえば、XML Http Request を使った非同期処理です。AngularJSはサーバとのデータ送受信に使用するためのモジュールが同胞されています。  下記のように「$http()」モジュールにて通信を行います。 hoge.js ## Ajax通信 ###################### var myApp = angular.module('myApp'); myApp.controller('MyController', ['$scope','$http', function($scope, $http) { $scope.execute = function() { $http({ method: 'GET', url: '/request/post.php' }). success(function(data, status, headers, config) { // 正常に処理が終了した際に非同期で実行 }). error(function(data, status, headers, config) { // エラーが発生した際に非同期で実行 }); }; }]);  レスポンスコードが「2xx」の場合には「success」が実行され、それ以外の場合には「error」が実行されます。   ③双方向バインディング  こちらもAngularJSを代表する機能です。  下記のようにモデルとinputフィールドをバインドすることができ、JavaScriptによるモデルの変更とユーザの入力によるフィールドの変更が双方向になります。 index.html <!-- ## 双方向データバインディング --> <input type="text" ng-model="message"> <div>{{message}}</div>   ④HTMLテンプレート  AngularJSでは、テンプレート言語にHTMLを使用し制御構造やUIコンポーネントはカスタム属性として使用します。 「エクスプレッション構文(「{{」と「}}」でくくる形式)」を使用してロジックを記述することも可能です。 index.html <!-- ## 文字列出力 --> <h1>{{ title }}</h1> <!-- ## ロジックの記述 --> <div>{{ (price + tax ) * count }}</div>  おわりに AngularJSの特徴はわかりましたでしょうか。 WEBフレームワーク、中でもJavaScriptフレームワークだけで見てもほかにもたくさんございます。 それぞれに特徴がありますので、違いを理解して必要に応じて導入を検討していくのがよいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[jest]localStorageをjestでテストしたい

やりたいこと localStorageのテストをjestでしたかったのですが、 jest初心者で忘れそうなのでメモ的に残しておこうと思います。 コード js(react) 実際のコードを書いていきます。(簡単に) 雑に書いてるのでミスがあったらすみません。 export const sample = () => { const ini = {}; const [sampleData, setSampleData] = useState(ini); useEffect(() => { const getItem = localStorage.getItem('item'); if (!getItem) { const sampleText = "sampleです"; localStorage.setItem('item', sampleText); setSampleData(sampleText); } else { setSampleData(getItem); } }, []); } jest import {renderHook } from '@testing-library/react-hooks'; import sample from "./" // 上記のファイルを呼び出し describe("ここに任意のテスト名", () => { test.each([[''], ['item']])("ここにテストの内容", (item) => { const spySet = jest.spyOn(Storage.prototype, "setItem"); const spyGet = item ? jest.spyOn(Storage.prototype, "getItem").mockReturnValue(item) : ''; const { result } = renderHook(() => sample()); if (item) { expect(spyGet).toHaveBeenCalledTimes(1); expect(spyGet).toBeCalledWith("item"); } else { expect(spySet).toHaveBeenCalledTimes(1); expect(spySet).toBeCalledWith("item", "sample"); } }); }); 解説 上記のコードで何をやっているか簡単に解説させてください。 まず、localStorage.getItemで該当のkeyを持ったstorageが存在するかを確認し、 あったらstateに値を保存。(値はlcoalStorage.getItemの値) なければ、setItemし、stateを更新というだけのことをしています。 jestの方の解説ですが、 上から順に説明します。 each eachは設定した配列の分だけテストを実行してくれます。 以下は3回testを回します。 .each([ [1],[2],[3] ]) こちらの値を参照するときは、test("", Fn)の引数に設定することで参照することができます。 spyOn 関数のモック化をします。 spyOnの第一引数に該当のオブジェクト、第二の引数にメソッドを指定することで該当の関数を モック化できます。 mockReturnValue モック.mockReturnValue('test'); とするとモックが実行された際の戻り値がmockReturnValueに設定された引数になります。 renderHook カスタムフックを呼ぶための関数で、今回の場合だとuseEffectの実行です。 toHaveBeenCalledTimes toHaveBeenCalledTimesは該当の関数が何回呼ばれたかを返します。 toBeCalledWith toBeCalledWithは該当の関数が実行された際の引数を返します。 まとめ 曖昧な部分が多く、間違っている部分があるかもしれないのでもし違う場合は教えてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

jsxとvueの条件によってタグを表示させる方法

概要 最近react,vueを触る機会が多いので、メモするほどのことでもないのですが、 初心者やreact,vueってどんな感じなの?って人用に書かせてもらいます。 (シリーズ化して、小出しに記事にしていくかも?) vueでの条件によって表示させる方法 vueでは表示したい要素のタグの属性にv-ifを追加することで 要素を表示するか、しないかを表現できます。 <template> <div> <span v-if="flag">表示されます</span> <span v-else>表示されません</span> </div> </template> <script> export default { data() { return { flag: true } } } </script> vueでの出しわけ方法は分かりやすく、 タグにv-if="~~"というディレクティブ(※)を追加することで、簡単に出しわけができます。 もちろん、v-else-ifも使えます。 ※ DOM要素に対して何かを実行することをvue側に伝えるものと覚えておくといいかもしれないです。 jsxでの条件によって表示させる方法 jsxの場合は以下になります。 const flag = true; return ( <div> {flag && <span>表示されます</span>} // or {flag ? <span>表示されます</span> : <span>表示されない</span>} </div> ) jsxの場合は{}を記述して、中に条件を書くことでタグの出しわけができます。 flagの管理などはstateと呼ばれるものを使用したりしますが、それはまた別の機会に。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】ページ遷移せずにいいねをしたい/取り消したい

みなさん、こんにちは! 筆者は大学生限定のプログラミングスクール「GeekSalon」でメンターをしています! 興味のある方や話だけでも聞いてみてい方はぜひのぞいてみてください? さっそく今回の本題に入っていきます! 今回は投稿に対するいいねを、ページ遷移せずともできる/取り消せるようにしていきたいと思います。 なお、いいね機能は実装済みという前提で話を進めていくため、いいね機能をまだ実装していない人は先にそちらの実装をお願いします。 また今回の実装では部分テンプレートを用いています。部分テンプレートについての理解が怪しい方は、参考となる記事を載せておきますので、そちらも参照してください! 実装環境 ruby 2.7.4p191 (2021-07-07 revision a21a3b7d23) [x64-mingw32] Rails 6.1.4.1 (※投稿機能、投稿に対するコメント機能は実装済みという前提で記事を書いていきます。) 実装① ~Javascriptを使えるようにする~ ページ遷移をせずに動的なプロセスを実行する方法はいくつかありますが、今回はJavascriptを用いて実装していきます。そのためにまずはJavascriptを使うことができるように記述を加えていきましょう。Javascriptと聞いて身構えたひともいるかもしれませんが、そんなに難しいプロセスは必要ないため安心してください。 まずは、view/layouts/application.html.erbの該当箇所に以下の記述を加えていきます。 view/layouts/application.html.erb <head> #省略 <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> #←この1行を追加 #省略 </head> これでJavascriptの記述が有効になりました。 実装② ~Viewファイルを整えよう~ Javascriptを使えるようにしたため、次はViweファイルを変更していきます。 まずは、view/likes/の配下に、_like.html.erbとcreate.js.erbとdestroy.js.erb```の3つのファイルを作成します。1つ目のファイルはアンダーバー(_)から始まる部分テンプレートであるということ、そして後半2つはhtmlファイルではなくjsファイルであるということに注意しつつファイルを作りましょう。 この後半2つのjsファイルが、likesコントローラーのcreateアクションとdestroyアクションの実行に対応したファイルとなります。 では、作成した3つのファイルにそれぞれ記述を加えていきましょう。 まずは_like.html.erbファイルへの記述です。このファイルには、投稿一覧のviewページに記述してある、いいねボタンに関する記述をそのままコピーしてきて貼り付けましょう。 貼り付けた結果は以下のようになります。 view/likes/_like.html.erb <% if user_signed_in? %> <% if current_user.already_liked?(t) %> <%= link_to tweet_like_path(id: t.id, tweet_id: t.id), method: :delete do %> <p>いいねを取り消す</p><%= t.likes.count %> <% end %> <% else %> <%= link_to tweet_likes_path(id: t.id, tweet_id: t.id), method: :post do %> <p>いいね</p><%= t.likes.count %> <% end %> <% end %> <% else %> <p>いいねの数 = </p><%= t.likes.count %> <% end %> さて、では2つのjsファイルにも記述を加えていきましょう。 それぞれのファイルに以下の記述を張り付けてください。 なお、@tweet(やt)といった変数は、自身のプロダクトに対応したものに書き換えてください。(変数tはlikes/_like.html.erbで用いた変数と同じものにする) view/likes/create.js.erb $('#likes_buttons_<%= @tweet.id %>').html("<%= j(render partial: 'likes/like', locals: {t: @tweet}) %>"); view/likes/destroy.js.erb $('#likes_buttons_<%= @tweet.id %>').html("<%= j(render partial: 'likes/like', locals: {t: @tweet}) %>"); 最後に、投稿のページ(投稿一覧ページや投稿詳細ページ)にて、_like.html.erbの記述が反映されるように、それぞれ以下の記述を加えてください。 なお、@tweetやtといった変数は、自身のプロダクトに対応したものに書き換えてください。 view/tweets/index.html.erb <div id="likes_buttons_<%= t.id %>"> <%= render partial: 'likes/like', locals: { t: t } %> </div> view/tweets/show.html.erb <div id="likes_buttons_<%= @tweet.id %>"> <%= render partial: 'likes/like', locals: { t: @tweet } %> </div> タグについているidは、create.js.erbとdestroy.js.erbとこの記述を紐づけるためのもの、<%= render ~ %>の記述は_like.html.erbを呼び込むための記述です。 さて、ここまでの記述でViewファイルは完成です。 実装③ ~コントローラーの記述変更~ 最後に、likes_controller.rbの記述を変更していきます。 まずは、viewにあるjsファイルが変数@tweetを受け取ることができるように、@tweetを定義していきます。 また、Javascriptでいいね/いいね取り消しを動的に行えるようにしている状態のため、redirectの記述も消していきます。 変更前と変更後は以下のような感じです。 変更前 likes_controller.rb def create like = current_user.likes.create(tweet_id: params[:tweet_id]) #user_idとtweet_idの二つを代入 redirect_back(fallback_location: root_path) end def destroy like = Like.find_by(tweet_id: params[:tweet_id], user_id: current_user.id) like.destroy redirect_back(fallback_location: root_path) end 変更後 likes_controller.rb def create @tweet = Tweet.find(params[:tweet_id]) like = current_user.likes.create(tweet_id: params[:tweet_id]) end def destroy @tweet = Tweet.find(params[:tweet_id]) like = Like.find_by(tweet_id: params[:tweet_id], user_id: current_user.id) like.destroy end 以上で実装は完了です! rails sをして、自分のプロダクトでいいねボタンを押してみてください! ページ遷移せずに、その場でいいねができるようになっているはずです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React + TypeScript: Facebookの状態管理ライブラリRecoilを使ってみる

RecoilはReactの状態を管理するライブラリで、Facebook改めMetaが実験的に開発しています。本稿執筆時の最新バージョンは0.5.2です。状態をひとまとめにするのではなく、ひとつひとつ細かく分けて管理します。ざっくりとお伝えするなら、useStateの状態をコンポーネントツリー内にまたがって共有するイメージです。 本稿は公式サイトの「Getting Started」で紹介されたコードサンプルを、モジュールに分けた作例に書き替えて解説します(サンプル001)。また、TypeScriptによる型づけも加えました。 サンプル001■React + TypeScript: Recoil example >> CodeSandboxへ React + TypeScriptのひな形アプリケーションをつくる Reactアプリケーションのひな形は、Create React Appでつくることにします。オプションとして--template typescriptを加えれば、TypeScriptの環境が簡単に加わえられて便利です(「Create React AppでTypeScriptが加わったひな形アプリケーションをつくる」参照)。 インストール Recoilは、npmあるいはyarnでつぎのようにインストールしてください。 npm install recoil yarn add recoil コンポーネントツリーを<RecoilRoot>でつつむ まず、状態を共有したいコンポーネントツリーのルートは、<RecoilRoot>で包んでください。すべての子孫コンポーネントから、同一の状態が使えるようになります。ここでは、親コンポーネントをCharacterCounterとしました。 src/App.tsx import { RecoilRoot } from 'recoil'; import { CharacterCounter } from './CharacterCounter'; function App() { return ( <RecoilRoot> <CharacterCounter /> </RecoilRoot> ); } export default App; atomで状態を定める atom()は、状態をひとつひとつ定める関数です。<RecoilRoot>に包まれたツリー内のすべてのコンポーネントから、同じ状態の値が読み書きできます。atomの値を参照するコンポーネントは、暗黙的に購読対象となる仕組みです。atomが更新されると、購読対象のコンポーネントは再描画されます。atomに渡すオプションオブジェクトには、一意の識別子keyとデフォルト値defaultを与えてください。 src/textState.ts import { atom } from 'recoil'; export const textState = atom({ key: 'textState', // 他のatomやselectorに対して一意のID default: '', // デフォルト値(初期値) }); <RecoilRoot>に包んだ親コンポーネントCharacterCounterには、このあと定めるふたつの子コンポーネント(TextInputとCharacterCount)が加えられます。 src/CharacterCounter.tsx import { TextInput } from './TextInput'; import { CharacterCount } from './CharacterCount'; export const CharacterCounter: React.VFC = () => { return ( <div> <TextInput /> <CharacterCount /> </div> ); }; コンポーネントからatomの読み書きをするために用いるのがuseRecoilState()フックです。構文はuseStateと同じで、コンポーネントツリーの外にある状態を共有して使えます。 状態がコンポーネントの外にあることを除けば、useStateフックとやっていることは変わりません。<input type="text">要素に入力した値が設定関数setText()で状態を書き替え、状態変数textの値はテキストとして表示されます。 src/TextInput.tsx import { useRecoilState } from 'recoil'; import { textState } from './textState'; export const TextInput: React.VFC = () => { const [text, setText] = useRecoilState(textState); const onChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { setText(event.target.value); }; return ( <div> <input type="text" value={text} onChange={onChange} /> <br /> Echo: {text} </div> ); }; selectorで状態の値に手を加えて返す 複数のatomから参照した値に手を加えて返すのがselector()です。他のselectorから値を得ることもできます。派生の状態をつくる純粋な関数です。引数として渡すオプションオブジェクトのget()に定めたコールバックは、状態の値にもとづいて処理した結果を返します。引数から取り出すget()が値を参照するための関数です。 charCountStateはtextStateからtextを得て、その文字数を返します。 src/charCountState.ts import { selector } from 'recoil'; import { textState } from './textState'; export const charCountState = selector({ key: 'charCountState', // 他のatomやselectorに対して一意のID // 状態の値にもとづいて処理した結果を返す get: ({ get }) => { const text = get(textState); return text.length; }, }); selectorの返す値を読み込むには、フックuseRecoilValue()を用いてください。コンポーネントCharacterCountが表示するのは、textStateに設定された文字数です。でき上がった作例の動きは、冒頭のサンプル001でご確認いただけます。 src/CharacterCount.tsx import { useRecoilValue } from 'recoil'; import { charCountState } from './charCountState'; export const CharacterCount: React.VFC = () => { const count = useRecoilValue(charCountState); return <>Character Count: {count}</>; };
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WebCrypto APIがundefinedになることがあるのは仕様でした

WebCrypto API (window.crypto.subtle)が'undefined'になって悩んで色々調べたら WebCrypto APIは「Secure Contexts」でないと使えないとのことだった。 詳細 MDN: WebCrypto APIが非安全なコンテキストで使用できないことを問題にする話は、 chromiumやらFireFoxのIssueに出てくるが 既にW3Cで決めていることらしいのでそこを変えない限りは各ブラウザは仕様通りということなので正常な動作。 このコメントみたいに社内システムで使おうとして、引っ掛かりました。 MDNには上記の通り「安全なコンテキストに制限されている機能」のページはあるのだけど、 「WebCrypto API」のページには書いていないのではまり期間が長くなってしまった。 Secure Contextsとは これを読めばいいけど雑に言うと、 「httpsかwssもしくはホストが自分自身(アドレスが127.0.0.1/8(ip6だと::1/128)かfile://」ならSecure Contexts。 localhost(127.0.0.1)で動くからって別サーバーに置いたとたんに動かなくなるとか起こる(起きた)。 おまけ これが原因だったかわからないが、こんなことが調べている最中に見つかったりした
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む