20210611のJavaScriptに関する記事は12件です。

JavaScript基本文法

変数定義 var 再定義、再代入可能な書き方で今はあまり主流ではないです。 const 後から書き換えることのできない変数を定義する書き方で、再代入・再定義共に不可という制約があります。 値が変わらない変数を定義する際に使用します。 let 後で書き換えることのできる変数を定義する書き方で、再代入は可能だが、再定義は不可という制約があります。 値が変わる変数を定義する際に使用します。 条件分岐 ・条件式を()でまとめる ・条件式後に続く{}の処理が実行される ・複数条件の場合はelse ifを使う if (条件式1) {  条件式1がtrueの時の処理 } else if (条件式2) {  条件式1がfalseで条件式2がtrueの時の処理 } else { 条件式1も条件式2もfalseの時の処理 }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Vuetify] v-combobox や v-autocomplete のプレースホルダーが表示されない問題

非フォーカス時にプレースホルダが表示されない Vuetifyのあるバージョンから、v-combobox や v-autocomplete において、フォーカスが当たっていない状態ではプレースホルダが表示されない不具合がある。 どうやら、チップ表示時に限定の不具合らしい。 対策 単純に不具合らしいので、そのうち治ると思うが、v2.5.0 の時点では発生していたので対応策が必要です。 Vuetifyの指定を下記のCSSで上書きしてやれば治ります。 .v-autocomplete:not(.v-input--is-focused).v-select--chips input { max-height: inherit; } inputの高さがゼロになっているのが原因みたいですね。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React-Reduxに関する理解

はじめに React+React-Reduxを用いてWebシステムを開発しているの際に引っかかった所やよく分からなかった箇所の復習用にこのような記事を投稿しようと考えました。 Reduxってなに? 簡単に説明すると、ReduxとはUIの状態を簡単に管理できるフレームワークです。 このReduxをReactと組み合わせて使う場合、UIの状態を専用の場所(ストア)で管理し、Reactはそれを表示するだけの役割を担っています。 フロー全体図 画面から入力されたInputをもとにAction Creatorからactionがdispatchされる Reducerがdispatchに対してStore内のstateを更新する 更新されたstateを参照する Store コンポーネントの状態(state)を集約している場所 ActionとActionCreator Storeに対して何か処理を行う場合は、Actionを発行します。そのActionを発行するための関数としてActionCreatorが存在します。 Reducer Actionが発行された時、このReducerが反応します。Reducerが発行されたActionに反応するとStore内のStateを変更します。 connect Reactのコンポーネント単体では、Reduxを利用することはできません。Reduxを使えるようにするためにはReact-Reduxのconnectという関数を用いて下記のように書きます。 1 export default connect( 2 (state) => (state.myStore), 3 (dispatch) => bindActionCreators({ ...myStore.actionCreators }, dispatch) 4 )(MyComponet); 2行目 storeのstateをpropsとしてコンポーネントに渡す。 3行目 発行したactionを指定する。 4行目 どのコンポーネントにstoreを接続するのか指定する。 mapStateToPropsとmapDispatchToProps mapStateToPropsは、コンポーネントに渡したいstateを入れることができます。 mapDispatchToPropsは、actionをstoreにdispatchしてくれる関数です。 最後に ここまで自分の理解できている範疇で書いてみましたが、まだまだ不明瞭な点が多いのが正直なところです。 さらに勉強して知識を蓄えていきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactにおけるアロー関数

要するに、関数オブジェクトのことです(´ω`) (誰に向けて書こうかな・・・う~ん、JSの初心者向けで) Reactは1ファイルに限り、HTMLのタグを、そのままScript内部に書く JSXという拡張機能を使うことが出来ます。 それはBabelというモジュールをインポートすることで、 使えるようになります。 <script src="https://unpkg.com/react@17/umd/react.development.js"> </script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"> </script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"> </script> <div id="JSX_root"></div> //JSXを使ったJavaScriptであることを宣言 <script type="text/babel"> //DOMセレクタ let jsxdom = document.querySelector("#JSX_root") //JSXの構文 let el = ( <div> <h2>タイトル/h2> <p>メッセージ/p> </div> ) // 仮想DOMをレンダリング ReactDOM.render(el, jsxdom) そして、JSX内部では、アロー関数と言うものを使うことが出来ます。 以下の例文を見てください。 let data2 = [ {name:'Taro', mail:'taro@yamada', age:45}, {name:'Hanako', mail:'hanako@flower', age:37}, {name:'Sachiko', mail:'sachiko@happy', age:29}, {name:'Jiro', mail:'jiro@change', age:18}, {name:'Kumi', mail:'kumi@class', age:56}, ] {data2.map((value) => ( <tr> <td>{value.name}</td> <td>{value.mail}</td> <td>{value.age}</td> </tr> ))} data2は連想配列、Dictionary型のオブジェクトの配列です。 そして、map関数の中で何やら書いていますね。 これはmap関数の拡張機能で、 map関数は、引数に関数オブジェクトを指定することが出来ます。 そして、map関数は「その配列の数だけ、引数に指定された関数の、戻り値を返却する という処理を書くことが出来ます map((引数。ループ処理なのでイテレーターと呼びます) => ( <tr> <td>{イテレーター.フィールド1}</td> <td>{イテレーター.フィールド2}</td> <td>{イテレーター.フィールド3}</td> </tr> )) そして、このような関数自体を引数に持つ、特殊な関数は 結構いっぱいあって、 このような書き方を、アロー関数と呼びます。(=> ← これね。矢印っぽいでしょ) 一般的な書き方はこんな感じ アロー関数に対応した特殊関数((引数) => (    中の処理 )) さらに、JSXの構文として、 アロー内部の関数をそのまま使うということも出来ます { (() => {中の処理})() } こうすると、 {}の中には、中の処理の戻り値が自動で設定されます。 (ぶっちゃけて言うと、何がいいんだろう・・・ ただ、JSXでは頻出の構文、らしい) コラム 今回はアロー関数と呼びましたが、一般的にはラムダ式と呼ばれているものです。 似たような機能は、他のプログラム言語にもたくさんありますよヾ(。>﹏<。)ノ゙✧*。 Java int[] numbers = {-1, 2, 0, -3, 8}; List<Integer> numbersList = new ArrayList<>(); for(int n : numbers) { numbersList.add(n); } // ソート方法として(引数1,引数2)->{return 引数1-引数2}を設定している // 処理の戻り値が0より大きいと、引数1を配列の上に、 // 処理の戻り値が0より小さいと、引数1を配列の下に、移動する // sort()メソッドの拡張機能である。 Collections.sort(numbersList, (a, b) -> { return a - b; }); 他にも例えばGUIアプリケーションで 「ボタンに紐づくイベント処理を作る」時とか 基本的に、提供されてるフレームワークの処理をカスタマイズする時に使います。 割かしフレームワークをいじり始めたら、割と必須知識かも
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Denoの入出力インターフェース

DenoにはGoをモデルにした入出力インターフェースが実装されている。 概要 Denoの入出力APIであるDeno.File、Deno.conn、Deno.stdin、Deno.stdout、Deno.stderr、Deno.Process.stdin、Deno.Process.stdout、Deno.Process.stderrは共通のインターフェースを実装している。 (注:インターフェースというのはTypeScriptのinterfaceのこと) そのインターフェースとは、Deno.Reader、Deno.ReaderSync、Deno.Writer、Deno.WriterSync、Deno.Seeker、Deno.SeekerSync、Deno.Closerである。 これらのインターフェースは、対応する組み込みAPIや標準ライブラリとともに組み合わせて使うことで、いい感じに扱う事ができる。 実装一覧 以下のインターフェースが実装されている。 Deno.Reader Deno.ReaderSync Deno.Writer Deno.WriterSync Deno.Seeker Deno.SeekerSync Deno.Closer Deno.File※ファイル読み込み ○ ○ ○ ○ ○ ○ ○ Deno.conn※Http接続 ○ ○ ○ Deno.stdin ○ ○ ○ Deno.stdout ○ ○ ○ Deno.stderr ○ ○ ○ Deno.Process.stdin※サブプロセスのstdin ○ ○ Deno.Process.stdout※サブプロセスのstdout ○ ○ Deno.Process.stderr※サブプロセスのstderr ○ ○ メソッド一覧 Deno.ReaderとDeno.Writerを操作するための関数が標準ライブラリなどに用意されている。 Deno API Deno.Copy srcの出力をdstの入力にパイプする。 function Deno.copy(src: Deno.Reader, dst: Deno.Writer, options?: { bufSize: number }): Promise<number> 標準ライブラリ: std/io readAll rからUint8Arrayで内容を読み取る。非同期版。 function readAll(r: Deno.Reader): Promise<Uint8Array> readAllSync rからUint8Arrayで内容を読み取る。同期版。 function readAllSync(r: Deno.ReaderSync): Uint8Array writeAll wにUint8Arrayの内容を書き込む。非同期版。 function writeAll(w: Deno.Writer, arr: Uint8Array) writeAllSync wにUint8Arrayの内容を書き込む。同期版。 function writeAllSync(w: Deno.WriterSync, arr: Uint8Array): void readLines readerから文字列で入力を1行ずつ読み取る。 function readLines(reader: Deno.Reader, decoderOpts?: { encoding: string, fatal: boolean, ignoreBOM: boolean }): AsyncIterableIterator<string> readStringDelim delimを区切り文字として、readerから文字列で入力を読み取る。 function readStringDelim(reader: Deno.Reader, delim: string, decoderOpts?: { encoding: string, fatal: boolean, ignoreBOM: boolean }): AsyncIterableIterator<string> readDelim delimを区切り文字として、readerから入力をUint8Arrayで読み取る。 function readDelim(reader: Deno.Reader, delim: Uint8Array): AsyncIterableIterator<Uint8Array> readRange function readRange(r: Deno.Reader & Deno.Seeker, range: ByteRange): Promise<Uint8Array> readRangeSync function readRangeSync(r: Deno.ReaderSync & Deno.SeekerSync, range: ByteRange): Uint8Array copyN rの出力をnバイト分だけdstの入力にパイプする。 function copyN(r: Reader, dest: Writer, size: number): Promise<number> iter Deno.Readerを非同期イテレータに変換する。 function iter(r: Deno.Reader, options?: { bufSize: number }): AsyncIterableIterator<Uint8Array> iterSync Deno.Readerを(同期)イテレータに変換する。 function iterSync(r: Deno.ReaderSync, options?: { bufSize: number }): IterableIterator<Uint8Array> readableStreamFromReader Deno.ReaderをReadableStream<Uint8Array>に変換する。 function readableStreamFromReader(reader: Deno.Reader | (Deno.Reader & Deno.Closer), options: ReadableStreamFromReaderOptions): ReadableStream<Uint8Array> readerFromIterable Iterable<Uint8Array>かAsyncIterable<Uint8Array>をDeno.Readerに変換する。 function readerFromIterable(iterable: Iterable<Uint8Array> | AsyncIterable<Uint8Array>): Deno.Reader readerFromStreamReader ReadableStreamDefaultReaderをDeno.Readerに変換する。 function readerFromStreamReader(streamReader: ReadableStreamDefaultReader<Uint8Array>): Deno.Reader writableStreamFromWriter Deno.WriterをWritableStream<Uint8Array>に変換する。 function writableStreamFromWriter(writer: Deno.Writer): WritableStream<Uint8Array> writerFromStreamWriter WritableStreamDefaultWriterをDeno.Writerに変換する。 function writerFromStreamWriter(streamWriter: WritableStreamDefaultWriter<Uint8Array>): Deno.Writer BufReader Deno.Readerの高機能版? BufReader.create(reader)の形で作成する。 標準ライブラリの一部ではBufReaderを使う事ができる。 BufReader.create(r: Deno.Reader, size: number): BufReader BufWriter Deno.Writerの高機能版? BufWriter.create(writer)の形で作成する。 標準ライブラリの一部ではBufWriterを使う事ができる。 BufWriter.create(writer: Deno.Writer, size: number): BufWriter 標準ライブラリ: std/encoding 割愛…!!(バイナリ操作ができるらしい) 他のやり方 ここまで入出力インターフェースについて説明してきたが、よく使う基本操作は入出力インターフェースを使わなくてもできる。一例をあげる。 入出力系 console.log('Hello') console.table([{a: 1, b: 2}, {a: 3, b: 4}]) alert('Hello') // 出力後、エンターキーで確認を求める const result = confirm('yes or no') // yかnの入力を求める const input = prompt('名前を入力してください') // 文字列の入力を求める import {printf} from 'https://deno.land/std@0.98.0/fmt/printf.ts')) printf('Hello %s !\n', 'world') //=> Hello world ! ファイル読み書き const data = await Deno.readTextFile("hello.txt"); await Deno.writeTextFile("hello.txt", "Hello world\n"); await Deno.writeTextFile("hello.txt", "Hello world\n", {append: true}); // ファイルに追記する await Deno.writeTextFile("hello.txt", "Hello world\n", {create: false}); // ファイルが存在しない場合に作成しない Http通信 fetch('https://qiita.com/') まとめ Denoの入出力インターフェースは標準ライブラリと組み合わせて使うと便利。 特によく使うのがDeno.Copy()(入出力パイプ)とstd/ioのreadLines()(1行ごとに読み込み)。 ただし、基本的な操作については入出力インターフェースを使わなくてもできる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kintoneとOutlookを連携してスケジュール管理をする#03

経緯 kintoneのOutlookを連携してスケジュール管理をしたい。 けど検索して出てくる記事が古いため、アレンジしてなるべく最新のものに対応する。 要するに「Outlook連携 - kintoneからOutlookスケジュールを登録しよう!!」のOutlook連携をほぼサンプルのまま使っていたのだけど、先日急に動かなくなったので最新化対応したいということ。 やりたいこと MSAL v2 に対応してkintoneとOutlookのスケジュールを連携させたい。 kintone UI Component v1 対応したUIを構築したい。 FullCalendar.js を導入してカレンダー表示させたい。 参考サンプル こちらの2つのサンプルを参考にOutlook連携カスタマイズを行います。 1. Outlook連携 - kintoneからOutlookスケジュールを登録しよう!! 2. クイックスタート: PKCE 対応の承認コード フローを使用して JavaScript SPA 内でユーザーをサインインさせ、アクセス トークンを取得する 今回(本記事)のゴール サインアウトとボタン表示制御 記事一覧 #01.ボタンを表示 #02.サインイン #03.サインアウトとボタン表示制御 ← 当記事 サインイン後にサインアウトボタンを表示する 前回まででサインインできることが確認できました。 サインインに成功したらサインインボタンは非表示にし、サインアウトボタンを表示するようにします。 サインアウト処理の実装 まずはサインアウトの処理をMicrosoftのサンプルから実装します。 サインインの処理が終了したらサインアウトのボタンを表示させたいので、signIn をPromiseにします。 またusername を authPopupService の中にいれ、 sessionStorage から取得するようにも変更しています。 authPopup.js const myMSALObj = new msal.PublicClientApplication(msalConfig); let authPopupService = { username: sessionStorage.getItem('username') ? sessionStorage.getItem('username') : '', // サインイン情報による制御 selectAccount: function () { const currentAccounts = myMSALObj.getAllAccounts(); if (currentAccounts.length === 0) { return; } else if (currentAccounts.length > 1) { console.warn('Multiple accounts detected.'); } else if (currentAccounts.length === 1) { this.username = currentAccounts[0].username; sessionStorage.setItem('username', this.username); } }, // サインイン後の処理 handleResponse: function (response) { if (response) { this.username = response.account.username; sessionStorage.setItem('username', this.username); } else { this.selectAccount(); } }, // サインイン signIn: function () { return new kintone.Promise(function (resolve, reject) { myMSALObj.loginPopup(loginRequest) .then(function(response) { authPopupService.handleResponse(response); resolve(); }) .catch(function(error) { console.log(error); }); }) }, // サインアウト signOut: function () { const logoutRequest = { account: myMSALObj.getAccountByUsername(this.username), postLogoutRedirectUri: msalConfig.auth.redirectUri, mainWindowRedirectUri: msalConfig.auth.redirectUri }; myMSALObj.logoutPopup(logoutRequest); }, } サインイン後のボタン作成定義 uiSignedCreateForIndex を追加します。 この中にサインイン前のボタン領域を非表示にするため、削除する処理も入れています。 また、サインインしたユーザーを確認するためにユーザー名を表示するように追加しています。 サインインの呼び出しではPromiseの結果を受け取り、正常終了であれば作成したサインイン後のボタン表示領域の作成処理を実行するようにします。 ui.js // カスタマイズのメイン処理 let uiService = { ... // サインイン前のボタン表示設定 uiNotSignCreateForIndex: function (kintoneHeaderSpace) { if (typeof kintoneHeaderSpace === 'undefined') { return; } // ボタン配置領域を作成 this.data.ui.HeaderNotSigned = document.createElement('div'); // サインイン前のボタン表示 this.data.ui.btnSignIn = this.createButton(this.setting.ui.buttons.signIn, this.setting.i18n.button); this.data.ui.btnSignIn.addEventListener('click', function (event) { authPopupService.signIn() .then(function() { // サインイン後のボタンを表示 uiService.uiSignedCreateForIndex(kintone.app.getHeaderSpaceElement()); }); }); this.data.ui.HeaderNotSigned.appendChild(this.data.ui.btnSignIn); // 要素を配置 kintoneHeaderSpace.appendChild(this.data.ui.HeaderNotSigned); }, // サインイン後のボタン表示設定 uiSignedCreateForIndex: function (kintoneHeaderSpace) { if (typeof kintoneHeaderSpace === 'undefined') { return; } // サインインボタン表示領域を削除 if ($('.header-not-signed ')) { $('.header-not-signed ').parent().remove(); } // ボタン配置領域を作成 this.data.ui.HeaderSigned = document.createElement('div'); // ユーザー名 this.data.ui.userName = document.createElement('p'); this.data.ui.userName.className = 'signed-user-name'; this.data.ui.userName.innerText = authPopupService.username; this.data.ui.HeaderSigned.appendChild(this.data.ui.userName); // サインアウトボタン this.data.ui.btnSignOut = this.createButton(this.setting.ui.buttons.signOut, this.setting.i18n.button); this.data.ui.btnSignOut.addEventListener('click', function (event) { authPopupService.signOut(); }); this.data.ui.HeaderSigned.appendChild(this.data.ui.btnSignOut); // 要素を配置 kintoneHeaderSpace.appendChild(this.data.ui.HeaderSigned); }, // ボタンを作成 createButton: function (setting, lang) { if (typeof setting === 'undefined' || !setting) { return null; } let uiButton; let text = lang ? lang[setting.text] || setting.text || '' : setting.text || ''; let type = setting.type; let className = setting.className ? setting.className : ''; uiButton = new Kuc.Button({ text: text, type: type, className: className }); return uiButton; }, }; ... キントーンの一覧画面表示時にログイン状態を確認して、サインイン前ならサインインボタンを表示、サインイン後ならサインアウトボタンを表示するようにします。 myMSALObjからサインイン情報を取得し判断します。 ui.js ... // 画面表示時イベント kintone.events.on('app.record.index.show', function (event) { const currentAccounts = myMSALObj.getAllAccounts(); // 初期処理 uiService.init(); if (currentAccounts.length === 0) { // サインインボタンを表示 uiService.uiNotSignCreateForIndex(kintone.app.getHeaderSpaceElement()); uiService.signInProcess(); } else if (currentAccounts.length > 1) { console.warn("Multiple accounts detected."); } if (currentAccounts.length === 1) { // サインイン後 uiService.uiSignedCreateForIndex(kintone.app.getHeaderSpaceElement()); } }); ... ボタンを追加しているのでCSSも定義します。(こちらは見た目なのでお好みで) buttons.css .header-not-signed > button { display: inline-block; margin: 0 15px 15px 15px; } .header-signed > button { display: inline-block; margin: 0 15px 15px 15px; } .signed-user-name { display: inline-block; margin: 0 15px 15px 15px; vertical-align: bottom; } 動作確認 サインインして動作を確認しましょう。 サインインボタンが消え、ユーザー名とサインアウトボタンが表示されればOKです。 逆にログアウトした場合はサインインボタンが表示され、サインアウトボタンは表示されないことも確認しましょう。 スピナーと通知 画面が無機質に切り替わるだけなので、ユーザーに処理中であることや処理結果を通知するようにします。 ui.js の uiService にスピナーと通知の作成、表示処理を追加します。 ui.js ... // スピナーを作成 spinner: function (message) { return new Kuc.Spinner({ text: message }); }, // 通知を作成 notification: function (text, type, className) { return new Kuc.Notification({ text: text, type: type, className: className, }); }, // 通知を表示 notificationOpen: function (notification) { if (!notification || typeof notification.localName === 'undefined' || notification.localName !== 'kuc-notification') { return; } notification.open(); setTimeout(function () { notification.close() }, 3000); }, ... サインインボタン作成時にスピナーと通知も作成します。 サインイン処理の開始時にスピナーを表示し、終了したら非表示にして通知を表示します。 ui.js ... // サインイン前のボタン表示設定 uiNotSignCreateForIndex: function (kintoneHeaderSpace) { if (typeof kintoneHeaderSpace === 'undefined') { return; } // スピナー作成 this.data.ui.signInSpinner = this.spinner('Sign in...'); // 通知領域を作成 this.data.ui.signInNotification = this.notification('サインインしました!', 'success', 'options-class'); this.data.ui.signInErrNotification = this.notification('サインインしていません!', 'danger', 'options-class'); // ボタン配置領域を作成 this.data.ui.HeaderNotSigned = document.createElement('div'); // サインイン前のボタン表示 this.data.ui.btnSignIn = this.createButton(this.setting.ui.buttons.signIn, this.setting.i18n.button); this.data.ui.btnSignIn.addEventListener('click', function (event) { // スピナーを表示 this.data.ui.signInSpinner.open(); // サインイン authPopupService.signIn() .then(function () { // サインイン後のボタン表示 uiService.uiSignedCreateForIndex(kintone.app.getHeaderSpaceElement()); // スピナーの非表示と通知を表示 uiService.data.ui.signInSpinner.close(); uiService.notificationOpen(uiService.data.ui.signInNotification); }); }); this.data.ui.HeaderNotSigned.appendChild(this.data.ui.btnSignIn); // 要素を配置 kintoneHeaderSpace.appendChild(this.data.ui.HeaderNotSigned); }, ... サインインをキャンセルしたり失敗した場合も、スピナーの非表示と通知の表示を追加します。 authPopup.js // サインイン signIn: function () { return new kintone.Promise(function (resolve, reject) { myMSALObj.loginPopup(loginRequest) .then(function (response) { authPopupService.handleResponse(response); resolve(); }) .catch(function (error) { console.log(error); // スピナーの非表示と通知の表示 uiService.data.ui.signInSpinner.close(); uiService.notificationOpen(uiService.data.ui.signInErrNotification); }); }) }, スピナーと通知が表示されるようになりました。 次回 Outlookからスケジュールを取得し、kintoneに登録
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kintone JavaScript APIの使い方をさっくり把握

仕事でKintoneを扱うことになったので、勉強中です。 とりあえずサクッと概要を把握するために書きました。 Kintone JavaScript APIとは Kintone内で任意のJavaScriptコードを実行できるらしい。 Kintoneのイベントをトリガーに処理実行することも可能。 私はレコードが追加されたらSlack通知する処理を作ってみようとか思ってます。 コーディングガイドライン Kintone JavaScript コーディングガイドライン 作ったJSファイルをKintoneにインポート Kintoneのシステム管理画面を開く(多分権限必要) [JavaScript / CSSでカスタマイズ]を選択 適用範囲を選択 JSの適用範囲を指定する。 とりあえず最初はテストのため「kintoneのシステム管理者だけに適用」にしましょうとのこと。 ※何を選択してもゲストユーザには適用されないらしい アップロード欄からアップロードする 保存押下 ↓↓↓↓↓保存ボタンは左上にありました↓↓↓↓↓ これでアップロード完了。 イベントじゃない系のスクリプトだと画面操作したときに実行されてました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[React] useCallbackで作られる関数に対してgenericを使いたい

問題 import React from "react" interface Props {} interface CallbackProps { a: number b: string } interface CallbackReturn { c: boolean } const Test: React.FC<Props> = (props) => { const callback = React.useCallback<(props: CallbackProps) => CallbackReturn>( (props) => { const {a, b} = props return { c: true, } }, [] ) const x = callback({ a: 1, b: "弐" }) console.log('x.c:', x.c) return <></> } export default Test useCallback自体にはgenericで型付けが出来るんだけど、ここで言うcallback変数となった関数にはgenericは渡せない。 callback<Generic>(...) // こうしたい場合 解決 関数を返すuseMemoに切り替える。こうすることでdependencyも使え無駄に関数を生成することはないし、genericを渡せる関数にもなる。 import React from "react" interface Props {} interface CallbackProps<T> { a: T b: string } interface CallbackReturn { c: boolean } const Test: React.FC<Props> = (props) => { const callback = React.useMemo(() => function<T>( props: CallbackProps<T> ): CallbackReturn { const { a, b } = props return { c: true, } }, []) const x = callback<boolean>({ a: false, b: "弐" }) console.log('x.c:', x.c) return <></> } export default Test
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JaveScriptのテスト「jest」を使ってみたい

どうも、駆け出しエンジニアです よくわからないことをとりあえずの備忘録で書いてます 今日はjsのテストをjestでやってみよう 今回はvueでモデルとしてjsを書いたのでそれのテストをしていきます まずはjestの追加 yarnでjestを追加していきましょー その他諸々も yarn add jest babel-jest babel-core@^7.0.0-bridge.0 @babel/core @babel/preset-env yarn add @babel/plugin-transform-modules-commonjs .babelrcを作成。以下を追加 { "env": { "test": { "plugins": [ "@babel/plugin-transform-modules-commonjs" ] } } } 最前面に__tests__フォルダ作成 その中にテスト関数を作っていきましょ その前にchokidarでテストを保存したら自動で実行できるようにする chokidar "__tests__/*.js" "*.js" -c "yarn jest" 今回するテスト 今回やっていくテストはvueでwebサイトを作ってるんですけど、 GASを使用して、google spread sheetからデータを持ってくるときのテストです /* eslint-disable no-alert, no-console, no-undef */ import { User } from "../src/model/user"; describe("gasTest", () => { test("findByNum", async () => { let user = await User.makeUser("hogehoge"); expect(user.id).toBe("hogehoge"); expect(user.name).toBe("hoge"); }); }); 一応user.jsとbase.jsも乗っけておく user.js import { Base } from "./base"; export class User { constructor(array) { this.id = array[0]; this.name = array[1]; this.pass = array[2]; this.ticket = parseInt(array[3]); } static makeUser(id) { return Base.findOne(id).then((array) => { return new User(array); }); } } base.js import fetch from "node-fetch"; export class Base { static URL() { return "https://script.google.com //gasのurl"; } static findOne(id) { return fetch(this.URL() + "?id=" + id) .then((response) => { return response.json(); }) .then((json) => { return json.flat(); //返ってきたJsonファイルの各値を、表示するために代入。 }) .catch((err) => { console.log(err); }); } } これで動いたし!!大丈夫そうかな!! よし、寝るか!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vueのeslintとかprettierの設定をしよう!!

vueでwebサイトを作っていくよ 備忘録としてだから、気にせず書いていこう まずはvueをcreateするよ vue create hoge その後の設定は以下 ? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, Router, Linter ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a linter / formatter config: Prettier ? Pick additional lint features: Lint on save ? Where do you prefer placing config for Babel, ESLint, etc.? In package.json ? Save this as a preset for future projects? No eslintとかの設定を頑張ろう eslintの設定を変えていく yarn eslint --init yarn run v1.22.10 ? How would you like to use ESLint? To check syntax and find problems ? What type of modules does your project use? JavaScript modules (import/export) ? Which framework does your project use? Vue.js ? Does your project use TypeScript? No ? Where does your code run? Browser ? What format do you want your config file to be in? JavaScript The config that you've selected requires the following dependencies: eslint-plugin-vue@latest ? Would you like to install them now with npm? Yes よくわからなかったけど、下の記事を参考にしました 最初の初期設定でpackage.jsonに設定を書く。みたいな設定にしちゃったけど大丈夫かな笑 PrettierとESLintをVSCodeで使う(Vue) 記事通り.eslintrc.jsに追加 ちょっとエラー出ちゃったので、そこだけ変えました module.exports = { env: { browser: true, es6: true, }, extends: [ "eslint:recommended", "plugin:vue/essential", "plugin:prettier/recommended", ], globals: { Atomics: "readonly", SharedArrayBuffer: "readonly", }, parserOptions: { ecmaVersion: 2018, sourceType: "module", }, plugins: ["vue", "prettier"], rules: { "prettier/prettier": "error", }, }; 記事ではprettierrcにも追加しているけど、今回はしない .vscodeのsetting.jsonに以下を追加 { "workbench.colorTheme": "Default Light+", //ワークベンチのテーマ デフォルトの白 "editor.codeActionsOnSave": { "source.fixAll.eslint": true, "source.organizeImports": true, "source.fixAll": true }, "editor.formatOnPaste": false, "editor.formatOnSave": false, "editor.formatOnType": true, "eslint.validate": ["javascript", "javascriptreact", "vue", "typescript"], "vetur.format.defaultFormatter.css": "prettier", "vetur.format.defaultFormatter.scss": "prettier", "vetur.format.defaultFormatter.html": "prettier", "vetur.format.defaultFormatter.js": "prettier-eslint", "vetur.format.defaultFormatter.ts": "vscode-typescript", "vetur.validation.template": false } 設定完了!! おお、、これらをやったらいい感じにeslintも動くし、色とかもいい感じだ!! あとは、eslintignoreとか今度作ろうかな
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

replaceAll()がJSに実装されてたのに、自分のバージョンが上がってなかったことに気付いた話

はじめに JavaだとreplaceAllがあったので、特に困ったことがなかったですが JavaScriptにはなかったので、文字列内で該当する全てを置換する際、ヒトクセ必要でした。 最近になってES12でreplaceAll()が使える様になったことを知ったので試してみました。 初投稿なので、優しくしてください。 とりあえず、私の環境(Mac:Chrome, FireFox, Safari どれもさっき更新しました。 と Node.js v15.14.0)は元気に↓動いてます。 やってみた。 古の技術 let str = 'いっぱい置換しろ〜〜〜なんとしても置換しろ〜〜〜頑張って置換しろ〜〜〜'; str = str.split('しろ〜〜〜').join('してくれてありがと♪♪♪'); console.log(str); => いっぱい置換してくれてありがと♪♪♪なんとしても置換してくれてありがと♪♪♪頑張って置換してくれてありがと♪♪♪ lodashで同じこと書いてみる。 let str = 'いっぱい置換しろ〜〜〜なんとしても置換しろ〜〜〜頑張って置換しろ〜〜〜'; str = _.join(_.split(str, 'しろ〜〜〜'),'してくれてありがと♪♪♪') console.log(str); => いっぱい置換してくれてありがと♪♪♪なんとしても置換してくれてありがと♪♪♪頑張って置換してくれてありがと♪♪♪ ES12 let str = 'いっぱい置換しろ〜〜〜なんとしても置換しろ〜〜〜頑張って置換しろ〜〜〜'; str = str.replaceAll('しろ〜〜〜', 'してくれてありがと♪♪♪'); console.log(str); => いっぱい置換してくれてありがと♪♪♪なんとしても置換してくれてありがと♪♪♪頑張って置換してくれてありがと♪♪♪ 正規表現もいける口(どうせ中身は呪文に変わるから滅多に使うな。と自分に言い聞かせながら) let str = 'いっぱい置換しろ〜〜〜なんとしても置換しろ〜〜〜頑張って置換しろ〜〜〜'; str = str.replaceAll(/しろ〜〜〜/ig, 'してくれてありがと♪♪♪'); console.log(str); => いっぱい置換してくれてありがと♪♪♪なんとしても置換してくれてありがと♪♪♪頑張って置換してくれてありがと♪♪♪ いつも通りIEは置き去りの様でした。 おしまい ちなみに「え?いつから?」ってなったので、こちらのページにリンクを貼ったGitHubのドキュメント更新履歴追いました。 結果ボリュームが多かったので、そんな細かいことは気にしたら負けだな。という結論に至ってます。 とても小さなことですがsplit + joinで、えっとコレで分けて繋げて・・・ ってコードからreplaceAllで、あ〜全置換ね。と言葉として直感的に理解しやすくなるんじゃないかと思います。 ただ、フロントエンドで上記の様な文字列操作を行うことは個人的にはあまり好きではないので できればバックエンドに実装したいです。 ^ ^
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript勉強メモ① オブジェクトと組み込み関数

目次 1.よく使われるオブジェクト 2.構文 1. よく使われるオブジェクト 【documentオブジェクトで使われる関数】 getElementById() ... id属性を持つ要素を取得する getElementsByName() ... name属性を持つ要素を取得する createElement() ... 任意の要素を生成する write() ... 画面に文字列を出力する open() ... ドキュメントを開く close() ... ドキュメントを閉じる insertAdjacentHTML('挿入する場所', 挿入する要素) ... 要素を挿入する。挿入する場所はbeforebegin, afterbegin, beforeend, afterendの4つがあり、それぞれ挿入したい場所によって使い分ける。 documentオブジェクト一覧 【windowオブジェクトで使われる関数】 alert() ... アラート表示 confirm() ... 確認ダイヤログ表示,真偽値の結果をリターンする open() ... ウィンドウを開く print() ... ウィンドウを印刷する prompt() ... 入力ダイヤログ表示 <プロパティ> * location ... URL情報の取得 * name ... ウィンドウ名の取得・設定 windowオブジェクト一覧 2. 構文 forEach ... キーは省略可。処理がreturnで1行のみだったら() => 処理というように簡略化できる。引数も1つだけなら( )外してOK。変数とKeyの順番に注意。 配列.forEach((変数, Key) => { 処理 }); スプレット演算子(...) ...配列を値ごと持ってこれる。JavaScriptでは配列の代入は参照受け渡しであることを覚えておく。スプレット演算子を使わないで代入すると参照代入となる。 let a = [100, 120]; let b = [1, 5, ...a]; map ... 受け取った配列を処理して新しい配列に代入し直す。 let a = [100, 120]; const ary = a.map((変数) => { 処理 }); filter ... 受け取った配列を真偽値によって振り分け、新しい配列に代入し直す。 let a = [100, 120]; const ary = a.filter((変数) => { if(変数) { return true; } else { return false; } }); Object.key(オブジェクト) ... オブジェクトのキーを返す。 オブジェクト ... 配列のようなもので、キーがある。PHPの配列とは違って[ ]の中にキーを書くわけではないことに注意。 let a = { x: 100, y: 180, } // 一つ一つをプロパティという。 console.log(a.x) // 100 let b = [ {x: 100, y: 180}, {x: 50, y: 90}, ]; console.log(b[0].y) // 180
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む