Closed6

Remix+CloudflareでWebサイトを作る 34(ショートカットキーがInputにフォーカスしていると使えない、Linkはインライン要素、@remix-run/devのアプデ時にエラー)

saneatsusaneatsu

【2024-09-27】react-hotkeys-hooks<input />タグにフォーカスしているとショートカットを検知してくれない

背景

https://zenn.dev/link/comments/aa52060ae9fbc5

ここで選択した react-hotkeys-hooksで入力フォームにフォーカスしていると設定しているショートカットを検知しない

解決方法

https://react-hotkeys-hook.vercel.app/docs/documentation/useHotkeys/disable-hotkeys#enable-hotkeys-on-form-fields

公式の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>
  )
}
saneatsusaneatsu

【2024-09-28】Copilotの力を借りて国際化終わり

国際化対応9割くらいは終わった。
ローディング処理周りとか、エラーメッセージとか日本語だけどもう許してくれ(ホジホジ

国際化のためにJSONファイル書く時にVSCodeのCopilotが常に空気読んで適切な言語で補完してくれるからめちゃくちゃ楽だった。

https://zenn.dev/yhatt/articles/cfa6c78fabc8fa

こういうやるときが多いときこそView Transition APIみたいな別になくてもいい機能つけたくなる。

saneatsusaneatsu

【2024-09-29】<Link />を使うとレンダリング時に一瞬描画崩れが発生することがある

問題

以下のようなコンポーネントをブラウザをリロードして表示する。
① と ② は本来縦方向に並んでほしいが、スタイルが適用されず(?)一瞬だけ横並びになってしまうという問題が発生している。

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では?

https://zenn.dev/nogu66/articles/fd97352ed30e5a

これはNextだけどこっちは <Link />にスタイル適用させられるのか。

解決方法

<Link /><div />で囲った。

saneatsusaneatsu

【2024-09-29】エラー:Expected server HTML to contain a matching <div> in <a>.

背景

https://zenn.dev/link/comments/f54ca348c86c34

1つ上のスクラップをのようなコードを書いていたらインスペクタで発生していた。

原因

ChatGPTにきいてみる。

エラーについて

サーバーサイドレンダリング(SSR) とクライアントサイドでのレンダリングが一致しない場合に発生します。この問題は、特に<Link>タグや<a>タグ内で<div>タグなどブロック要素をネストしたときに見られることが多いです。<a>タグは通常インライン要素であり、その中に直接ブロック要素(<div>など)を配置するとHTMLの構造として不正とみなされることがあります。

原因

このエラーの主な原因は、サーバーとクライアントのレンダリングの違いです。サーバーサイドでは<Link>タグが適切にレンダリングされますが、クライアントサイドではブラウザがインライン要素内にブロック要素(<div>など)があるときに警告を出すことがあります。HTML仕様においては、<a>タグ(インライン要素)の中に直接ブロック要素(<div>など)を含めるのは推奨されていません。

解決策

<Link>タグや<a>タグの中に<div>のようなブロック要素をネストしないようにすることが必要です。代わりに、以下のようなアプローチを取ると、エラーを解消できます。

  1. <Link> タグをブロック要素に変換する
    <Link> タグ自体をブロック要素(<div> や block クラス)に変換し、<Link> の中にブロック要素を含めても問題が発生しないようにします。

要は <a><Link>) などのインライン要素の中にブロック要素を入れるのはアウト。

調べる

https://qiita.com/K-Kazuki/items/72885705c8c001806146#a-に-div-を入れていい条件

<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()を使うようにしないと挙動が意図しないものになるかも。
saneatsusaneatsu

【2024-09-29】エラー:@remix-run/dev2.12.1にアップデートするとTypeError: Invalid state: Controller is already closed が発生する

背景

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 ipnpm 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ブランチに取り込むとエラーは出ない状態になっている

一時的な対処すぎて根本的には解決してない。

saneatsusaneatsu

@remix-run/dev更新しなくても出た。
sassを更新しなくてもでる。

このスクラップは1ヶ月前にクローズされました