Remix+CloudflareでWebサイトを作る 34(ショートカットキーがInputにフォーカスしていると使えない、Linkはインライン要素、@remix-run/devのアプデ時にエラー)
react-hotkeys-hooks
で <input />
タグにフォーカスしているとショートカットを検知してくれない
【2024-09-27】背景
ここで選択した react-hotkeys-hooksで入力フォームにフォーカスしていると設定しているショートカットを検知しない
解決方法
公式のQuick Startのコードを使って説明する。
enableOnFormTags
のキーにフォームのタグ名を入力すると使えるようになる。
import { useHotkeys } from 'react-hotkeys-hook'
export const ExampleComponent = () => {
const [count, setCount] = useState(0)
- useHotkeys('ctrl+k', () => setCount(count + 1), [count])
+ useHotkeys(
+ "ctrl+k",
+ () => {
+ setCount(count + 1);
+ },
+ [count],
+ {
+ enableOnFormTags: ["input", "select", "textarea"],
+ }
+ );
return (
<p>
Pressed {count} times.
</p>
)
}
【2024-09-28】Copilotの力を借りて国際化終わり
国際化対応9割くらいは終わった。
ローディング処理周りとか、エラーメッセージとか日本語だけどもう許してくれ(ホジホジ
国際化のためにJSONファイル書く時にVSCodeのCopilotが常に空気読んで適切な言語で補完してくれるからめちゃくちゃ楽だった。
こういうやるときが多いときこそView Transition APIみたいな別になくてもいい機能つけたくなる。
<Link />
を使うとレンダリング時に一瞬描画崩れが発生することがある
【2024-09-29】問題
以下のようなコンポーネントをブラウザをリロードして表示する。
① と ② は本来縦方向に並んでほしいが、スタイルが適用されず(?)一瞬だけ横並びになってしまうという問題が発生している。
import { Link } from "@remix-run/react";
export function Test() {
return (
<Link to='/hoge'>
// ①
<img
className="min-h-60"
src='http://...'
/>
// ②
<div>
<p className="">
hogehoge
</p>
</div>
</Link>
);
}
調べる
ChatGPTに聞くとimgのheightの設定やらなんやら言われるが違いそう。
色々いじっていたら<Link />
を<div />
に変えるとこの問題が発生しないことに気がついた。
インライン要素だから
<Link />
を使ってブラウザのインスペクタを見ると<a />
タグになっているが、これはインライン要素からなのかなと考える。
A <a href> wrapper to enable navigation with client-side routing.
よく見たらRemixのドキュメントでもラッパーだと言っているしな。
じゃ、block
つけたらどうにかなるかな?と思ったけどこれでは治らず。
import { Link } from "@remix-run/react";
export function Test() {
return (
- <Link to='/hoge'>
+ <Link to='/hoge' className="block">
Next.jsでは?
これはNextだけどこっちは <Link />
にスタイル適用させられるのか。
解決方法
<Link />
を<div />
で囲った。
Expected server HTML to contain a matching <div> in <a>.
【2024-09-29】エラー:背景
1つ上のスクラップをのようなコードを書いていたらインスペクタで発生していた。
原因
ChatGPTにきいてみる。
エラーについて
サーバーサイドレンダリング(SSR) とクライアントサイドでのレンダリングが一致しない場合に発生します。この問題は、特に<Link>タグや<a>タグ内で<div>タグなどブロック要素をネストしたときに見られることが多いです。<a>タグは通常インライン要素であり、その中に直接ブロック要素(<div>など)を配置するとHTMLの構造として不正とみなされることがあります。
原因
このエラーの主な原因は、サーバーとクライアントのレンダリングの違いです。サーバーサイドでは<Link>タグが適切にレンダリングされますが、クライアントサイドではブラウザがインライン要素内にブロック要素(<div>など)があるときに警告を出すことがあります。HTML仕様においては、<a>タグ(インライン要素)の中に直接ブロック要素(<div>など)を含めるのは推奨されていません。
解決策
<Link>タグや<a>タグの中に<div>のようなブロック要素をネストしないようにすることが必要です。代わりに、以下のようなアプローチを取ると、エラーを解消できます。
- <Link> タグをブロック要素に変換する
<Link> タグ自体をブロック要素(<div> や block クラス)に変換し、<Link> の中にブロック要素を含めても問題が発生しないようにします。
要は <a>
(<Link>
) などのインライン要素の中にブロック要素を入れるのはアウト。
調べる
<a> の親要素のコンテンツモデルで、子孫に持てるとされているコンテンツモデルを持つ要素は <a> に入れることができます。
HTML5では許されるケースがあり、今回はそのケースに該当していそうなんだけどな。
ref: 【一覧表あり】HTML5でのタグの入れ子のルールを徹底まとめ|webliker(ウェブライカー)
とか思ってたら、原因ここじゃなかった。
コンポーネント化してたから忘れてたけど <Link>
の中で <Link>
を使っているのが原因だった。
修正
ということで中にはいっている<Link>
は<button>
に置き換える。
const navigate = useNavigate();
<Link to="/hoge">
<div className="link-content">
<button onClick={()=> navigate('/fuga')} >
Click me
</button>
</div>
</Link>
が、 <Link>
のなかの<button>
をクリックしてもonClick
に書いた挙動にならず、<Link>
に設定しているパスに遷移してしまう。
つまり/fuga
ではなく/hoge
に遷移してしまう。
どうやらonClick
自体は正しく発火しているがそれを<Link >
に設定しているパスが上書きしているっぽい。
解決方法
e.preventDefault();
を足せば治るが、なんだかどうもこれはきれいじゃない感じがするんだよな。
一旦進んでまた後で考えよう。
const navigate = useNavigate();
<Link to="/hoge">
<div className="link-content">
<button
onClick={(e) => {
e.preventDefault();
navigate('/fuga');
}}
>
Click me
</button>
</div>
</Link>
まとめ
-
<Link />
の中で<div />
を使うのはHTML5的にはOKな場合がある - 今回は
<Link />
の中で<Link />
を使って発生していた -
<Link />
の中で<button>
を使うようにする場合e.preventDefault()
を使うようにしないと挙動が意図しないものになるかも。
@remix-run/dev
を2.12.1
にアップデートするとTypeError: Invalid state: Controller is already closed
が発生する
【2024-09-29】エラー:背景
pnpm up --latest
で色々アップデート。
PR上でデプロイはうまく言っているからマージ。
mainブランチでpnpm dev
で立ち上げてみたら以下のエラーが発生していた。
More info: https://sass-lang.com/d/legacy-js-api
TypeError: Invalid state: Controller is already closed
at new NodeError (node:internal/errors:406:5)
at ReadableByteStreamController.close (node:internal/webstreams/readablestream:1148:13)
at close (/xxx/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom-server.browser.development.js:143:15)
at flushCompletedQueues (/xxx/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6906:9)
at abort (/xxx/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6951:7)
at EventTarget.listener (/xxx/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom-server.browser.development.js:7000:9)
at [nodejs.internal.kHybridDispatch] (node:internal/event_target:807:20)
at EventTarget.dispatchEvent (node:internal/event_target:742:26)
at abortSignal (node:internal/abort_controller:369:10)
at AbortController.abort (node:internal/abort_controller:391:5)
at EventTarget.abort (node:internal/deps/undici/undici:5225:21)
at [nodejs.internal.kHybridDispatch] (node:internal/event_target:807:20)
at EventTarget.dispatchEvent (node:internal/event_target:742:26)
at abortSignal (node:internal/abort_controller:369:10)
at AbortController.abort (node:internal/abort_controller:391:5)
at ServerResponse.<anonymous> (/xxx/node_modules/.pnpm/@remix-run+dev@2.12.1_@remix-run+react@2.12.1_sass@1.79.4_typescript@5.6.2_vite@5.4.8_wrangler@3.78.12/node_modules/@remix-run/dev/dist/vite/node-adapter.js:46:40)
at ServerResponse.emit (node:events:514:28)
at ServerResponse.emit (node:domain:488:12)
at emitCloseNT (node:_http_server:1023:10)
at process.processTicksAndRejections (node:internal/process/task_queues:81:21) {
code: 'ERR_INVALID_STATE'
}
調査
mainブランチで変更をもとに戻す
どのライブラリのせいでおきているか特定する。
node_module/
ディレクトリを削除してpackage.json
をもとに戻してpnpm i
、pnpm dev
を実行してみる。
が、それでも起きる。なんでだ?
なお、ビルドエラーは起きていない。
前のCommitに戻る
- mainブランチで、packageを元に戻す
- →エラーが起きる
- 1つ前のCommitに戻る
- →エラーが起きない
内容同じはずなんだけどな...。
node_modules/
を削除してpnpm prune
などを実行してみても変わらず。
原因となったパッケージとバージョン
以下のように@remix-run/dev
のバージョンを上げたときに発生したことがわかった。
これをpackage.jsonから削除してもエラーが起き続ける原因はわからなかった。
- "@remix-run/dev": "^2.11.2",
+ "@remix-run/dev": "^2.12.1",
結局どうしたか
mainからブランチ切る
→そこでpackage.jsonで更新するパッケージを増やしてエラーがでないか試す
→大丈夫だったらaddする
→エラーが出たらそこまでとしてPRをMergeする
→mainブランチに取り込むとエラーは出ない状態になっている
一時的な対処すぎて根本的には解決してない。
@remix-run/dev更新しなくても出た。
sassを更新しなくてもでる。