Chromeの拡張機能はHTML、JavaScript、CSSで作れますが、JavaScriptよりもReactの方が作りやすいので、やり方をご紹介します。
爆速でChrome拡張機能の作る もご覧いただければと思います。
「ReactでとりあえずChromeの拡張機能を作って動かす」を目的としているので、Reactの解説などは行わないのでご注意ください。
まずはReactのプロジェクトを作成します。
npm create vite@latest
Reactのプロジェクトが作成されたら、App.tsxを以下のように修正します。
function App() { return <button onClick={() => alert(1)}>テスト</button>;
}
export default App;
yarn build
or npm run build
でReactアプリをビルドします。
すると、distディレクトリが作成されます。
Reactアプリとは別にディレクトリを作成します(ここではchrome-extensionとします)。
そのchrome-extensionの中にmanifest.json
を作成し、さらにdistディレクトリ以下のファイル全てをコピーします。
chrome-extensionのディレクトリ構成とmanifest.jsonは以下のようになります。
{ "name": "Sample", "description": "Sample Extension. Show alert!", "version": "1.0.0", "manifest_version": 3, "action": { "default_popup": "index.html" }
}
あとは、Chromeから作成した拡張機能を読み込み(「パッケージ化されていない拡張機能を読み込む」からchrome-extensionのディレクトリを選択)すれば拡張機能が動かせます(具体的なやり方はこちらの記事を参照)
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!
日付のフォーマットして取得することができます。
const day = dayjs('2025-01-01 17:10:30')
day.format('YYYY-MM') // 2025-01
day.format('YYYY-MM-DD') // 2025-01-01
day.format('YYYY-MM-DD HH:mm:ss') // 2025-01-01 17:10:30
day.format('YYYY月M日D日') // 2025月1日1日
「◯日前」「◯週間前」「◯ヶ月前」「◯年前」などの日付を取得できます。
const day = dayjs('2025-01-01 17:10:30')
day.subtract(1, 'day').format('YYYY-MM-DD') // 2024-12-31
day.subtract(1, 'week').format('YYYY-MM-DD') // 2024-12-25
day.subtract(1, 'month').format('YYYY-MM-DD') // 2024-12-01
day.subtract(1, 'year').format('YYYY-MM-DD') // 2024-01-01
「◯日後」「◯週間後」「◯ヶ月後」「◯年後」などの日付を取得できます。
const day = dayjs('2025-01-01 17:10:30')
day.add(1, 'day').format('YYYY-MM-DD') // 2025-01-02
day.add(1, 'week').format('YYYY-MM-DD') // 2025-01-08
day.add(1, 'month').format('YYYY-MM-DD') // 2025-02-01
day.add(1, 'year').format('YYYY-MM-DD') // 2026-01-01
それぞれ年、月、日を取得できます。
const day = dayjs('2025-01-01 17:10:30')
day.year(); // 2025
day.month(); // 0 ※0〜11で取得されます
day.date(); // 1
月初や月末の日付を取得できます。
const day = dayjs('2025-06-15 17:10:30')
day.startOf('month').format('YYYY-MM-DD') // 2025-06-01
day.endOf('month').format('YYYY-MM-DD') // 2025-06-
day.startOf('year').format('YYYY-MM-DD') // 2025-01-01
day.endOf('year').format('YYYY-MM-DD') // 2025-12-31
日付の比較ができます。
const day1 = dayjs('2025-01-01 00:00:00')
const day2 = dayjs('2025-01-02 00:00:00')
const day3 = dayjs('2025-01-03 00:00:00')
day1.isBefore(day2) // true
day2.isAfter(day3) // false
day3.isSame(day1) // false
第二引数で日付のどの単位までで比較するかを指定できます。
const day1 = dayjs('2025-01-01 00:00:00')
const day2 = dayjs('2025-01-01 00:01:00')
console.log(day1.isSame(day2, 'year')) // true
console.log(day1.isSame(day2, 'month')) // true
console.log(day1.isSame(day2, 'date')) // true
console.log(day1.isSame(day2, 'hour')) // true
console.log(day1.isSame(day2, 'minute')) // false
console.log(day1.isSame(day2, 'second')) // false
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!
普通、JavaScript(TypeScript)で関数に引数を渡す場合、以下のようにします。
const hogeFunc = (hogeName: string, hogeValue: number, hogeFlag: boolean) => { // 処理
}
// 関数呼び出し
hogeFUnc('hoge', 55, true)
引数の数が少なければ、これでもいいかもしれません。
ただ、引数の数がもっと増えた場合や、デフォルト引数を使用する場合に問題になります。
例えば以下のような場合です。
const hogeFunc = ( hogeName: string, hogeValue: number, hogeFlag1?: boolean = false, hogeFlag2?: boolean = false, hogeFlag3?: boolean= false,
) => // 処理
};
hogeFunc("test", 12345, false, false, true)
hogeFlag1、hogeFlag2、hogeFlag3はオプショナル引数なので、省略できます。
でも、「hogeFlag3にtrueを渡したい。hogeFlag1とhogeFlag2はデフォルト値でOK」という場合はhogeFlag1とhogeFlag2にfalseを指定する必要があります。
必要な引数は3つだけなのに5つ全部書く必要があり面倒です。
また、引数の順番も気にする必要があり、上記のように同じ型の引数が並んでいると間違いも起こりやすいです。
上記をオブジェクトで渡すようにすると以下のようになります。
const hogeFunc = ({ hogeName, hogeValue, hogeFlag1 = false, hogeFlag2 = false, hogeFlag3 = false,
}: { hogeName: string; hogeValue: number; hogeFlag1?: boolean; hogeFlag2?: boolean; hogeFlag3?: boolean;
}) => { // 処理
}; hogeFunc({hogeName: "test", hogeValue: 12345, hogeFlag3: true})
必要な引数だけの指定でよく、オブジェクトのキーのおかげで「このtrueは何のフラグだ?」となることも減りそうです(サンプルなのでhogeFlagという名前ですが、実際にはわかりやすい名前で命名されるはず)
また、引数の順番も気にする必要がなくなります。
個人的には引数が3つまではOK、4つ以上はオブジェクト形式かなと思っています(boolean型のフラグがある場合は特に)
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!
プラグイン使ったほうが楽ですが、セキュリティの関係でプラグイン使用不可の場合もあると思うので、そんなときに使えます。
まず、Chromeでデベロッパーツールを開きます。
Macの場合はキーボードでCmd + Shift + Pを押します。
すると、以下のようなウィンドウが表示されます。
表示されたウィンドウで「スクリーン」と入力すると、以下のようにコマンドが絞り込まれて表示されるので、「フルサイズのスクリーンショットをキャプチャ」をクリックすれば、全画面のスクリーンショットを取得できます!
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!
Reactで「React has detected a change in the order of Hooks called by〜 . This will lead to bugs and errors if not fixed.」のエラーが発生した場合の対処法です。
上記エラーは、useStateなどのHooksが呼び出される順序が変わったときに発生するそうです。
Reactでは、Hooksはトップレベルで呼び出す必要があります。
フックをループや条件分岐、あるいはネストされた関数内で呼び出してはいけません。代わりに、あなたの React の関数のトップレベルでのみ、あらゆる早期 return 文よりも前の場所で呼び出してください。これを守ることで、コンポーネントがレンダーされる際に毎回同じ順番で呼び出されるということが保証されます。これが、複数回
useState
やuseEffect
が呼び出された場合でも React がフックの状態を正しく保持するための仕組みです
参考:https://ja.legacy.reactjs.org/docs/hooks-rules.html
そのため、if文や下記のような早期return文の後にHooksを書くとHooksの順序が変わってしまいエラーが発生します。
import { useEffect, useState } from "react";
const Sample = ({ count }: { count: number }) => { const [flag1, setFlag1] = useState(true); if (count === 0) { return <></>; } const [flag2, setFlag2] = useState(true); return <>{count}</>;
};
export default Sample;
Hooksは条件分岐内や早期return文の後ではなく、トップレベルに書く必要があります。
下記のように、早期return文より前にHooksを書けばエラーは発生しなくなります。
"use state";
import { useEffect, useState } from "react";
const Sample = ({ count }: { count: number }) => { const [flag1, setFlag1] = useState(true); const [flag2, setFlag2] = useState(true); if (count === 0) { return <></>; } return <>{count}</>;
};
export default Sample;
下記のように、コンポーネントとして切り出した場合もエラーは発生しません。
import { useEffect, useState } from "react";
const Parent = ({ count }: { count: number }) => { const [flag1, setFlag1] = useState(true); if (count === 0) { return <></>; } return <Children count={count} />;
};
const Children = ({ count }: { count: number }) => { const [flag2, setFlag2] = useState(true); return <>{count}</>;
};
export default Parent;
VSCodeでeslintの設定されていれば、コード書いているときに以下のようにエラーを表示してくれるので気付ける。
React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!
Chromeのデベロッパーツールで知っておくと便利な使い方をご紹介します。
デベロッパーツールを開き、右上の歯車 > 言語 で日本語を選択し、デベロッパーツールを開き直すと日本語になります。
変数や条件分岐でconsole.logを出して検証するということはよくあると思いますが、画面遷移をすると消えてしまいます。
コンソールタブ上部にある「ログを保持」をチェックをすると画面遷移してもログが消えずに残ります。
ネットワークタブで、APIのリクエストやレスポンスを確認したいこともよくあると思いますが、これも画面遷移をすると消えてしまいます。
ネットワークタブ上部にある、「ログを保持」をチェックすると画面遷移してもログが消えずに残ります。
ネットワークタブのログはデフォルトだと以下のように表示されます。
Name列にはAPI名やファイル名が表示されますが、エンドポイントは行を選択してヘッダーを見ないとわかりません。
ネットワークタブ上部にある、「大きなリクエスト行」をタップすると、エンドポイントも表示されるようになります。
低速なネットワークの状態で、どのような挙動になるか確認したいこともあると思います。
ネットワークタブで、「スロットリングなし」をクリックし、「高速 3G」や「低速 3G」を選択すると低速なネットワークでWebアプリの挙動を確認できます。
ローカルストレージ、セッションストレージ、Cookieは、アプリケーションタブから確認できます。
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!
ただ、iPhoneのSafariでは単体ではデベロッパーツールを使うことはできません。
iPhoneとMacを使用して、「iPhoneのSafariで開いているページのデベロッパーツールをMacで開く方法」をご紹介します。
1. MacでSafariを起動します
2. iPhoneとMacをケーブルで接続します
3. iPhoneのSafariを再起動します
4. iPhoneのSafariで、デベロッパーツールを使用したいページを開きます
5. MacのSafariのメニューバーの「開発」をクリックします
6. 以下のような表示になっているはずなので、iPhoneにカーソルを乗せます
7. デベロッパーツールを使用したいページ(タブ)をクリックします
8. iPhoneのSafariで開いているページのデベロッパーツールが起動します!
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!
defaultValues
にセットしたいことがあると思います。"use client";
import { useForm } from "react-hook-form";
import useSWR from "swr";
export default function Home() { const fetcher = () => fetch("/user/1").then((res) => res.json()); const { data, isLoading } = useSWR( "/user/1", fetcher ); const { register } = useForm({ defaultValues: { name: data?.name, }, }); return <input {...register("name")} />;
}
しかし、このやり方だとdefaultValuesにうまくセットされません。
なぜなら、data
はフェッチしたデータが入るまではundefined
となっているため、defaultValues
にはundefinedがセットされてしまうためです。
データがフェッチされても、defaultValuesは上書きされないんですね。
この現象は、useEffect
を使用すれば回避できます。
"use client";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import useSWR from "swr";
export default function Home() { const fetcher = () => fetch("/user/1").then((res) => res.json()); const { data, isLoading } = useSWR( "/user/1", fetcher ); const { register, reset } = useForm(); useEffect(() => { if (isLoading) return; reset({ name: data?.name }); }, [data, isLoading, reset]); return <input {...register("name")} />;
}
useEffectの依存配列にSWRのdataを指定しています。
SWRでデータがフェッチできたタイミングでuseEffectが実行され、RHKのreset
で初期値をセットされます。
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!
reset
は「Formを空にする」という理解でいましたが勘違いしていました。"use client";
import { useForm, SubmitHandler } from "react-hook-form";
export default function Home() { const { register, reset } = useForm({ defaultValues: { hoge: "test", }, }); return ( <> <input {...register("hoge")} /> <button onClick={() => { reset(); }} > リセット </button> </> );
}
上記は、defaultValues
でhogeの初期値に「test」を設定しています。
hogeの値を変更後、リセットボタンを押下するとhogeの値は空ではなく「test」になりました。
値を空にするにはreset({ hoge: "" })
とするか、setValue
を使用してsetValue("hoge", "")
とすればできました。
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!
refreshInterval
を使用すると実現できます。
"use client";
import { useEffect, useState } from "react";
import useSWR from "swr";
const fetcher = (url: string) => fetch(url).then((r) => r.json());
export default function Home() { const [status, setStatus] = useState(false); const { data } = useSWR("http://localhost:3100/api/users", fetcher, { refreshInterval: !status ? 5000 : 0, }); useEffect(() => { if (data.status === "OK") { setStatus(true); } }, [data]); return <>〜省略〜</>;
}
上記の例では、5秒おき(5000ミリ秒)に再検証するようにしています。
refreshInterval
は0を指定すると自動再検証がストップするので、再検証したレスポンスをもとに再検証を止めるようにしています。
setIntervalなどを使って自作する必要がないので便利です。
IT技術ブログ
↓↓「にほんブログ村」のランキングに参加しています。少しでも面白い、参考になったとか思われたらポチッとしていただけると嬉しいです!