🍠

Astro アイランドの React コンポーネントに class 名を props で渡す Tips

に公開

はじめに

Astro テンプレート内に配置した React コンポーネントに class 属性を props で渡そうとしてハマったメモです。
Astro には入門したばかりなので、用語含め間違いがあればご指摘ください 🙏

⚠️ Astro から class 属性で React にクラス名を渡しても受け取れない

Astro のテンプレートでは class 名は通常の HTML と同じで class="foo" なので、見た目を揃えたくて React コンポーネントにも class="" でクラス名を渡そうとしたが常に undefined になってしまった

/src/components/MyComponent.tsx
type MyComponentProps = {
  class?: string;
};

export function MyComponent({ class: className }: MyComponentProps) {
  return (
    <div className={className}>...</div>
  );
}
/src/pages/index.astro
---
import { MyComponent } from '@/components/MyComponent';
---
<main>
  <MyComponent client:load class="foo" />
</main>

class 属性で Astro から React の <MyComponent /> に props としてクラス名を渡そうとしているが props.class は常に undefined になってしまう

📝 class React 単体では警告が出るが string として値が渡される

React では className を使うべきだが誤って class を使った場合、警告は出るものの string として値が渡される (class がそもそも JavaScript の予約語なので使い方としてよくはない)

app.tsx
export function App() {
  return <MyComponent class="foo" />;
}

=> Warning: Invalid DOM property `class`. Did you mean `className`?

🚀 Astro は React に class で className を渡そうとするとサポート外のプロパティとして undefined にする

🚨 This even works for class, which is not supported by React. 🚨

Differences between Astro and JSX
Astro component syntax is a superset of HTML. It was designed to feel familiar to anyone with HTML or JSX experience, but there are a couple of key differences between .astro files and JSX.
In Astro, you use the standard kebab-case format for all HTML attributes instead of the camelCase used in JSX. This even works for class, which is not supported by React.
cf. Astro Template expressions reference - Differences between Astro and JSX

Astro は React コンポーネントに class を渡す際に className に変換してくれるわけではない。
React ではサポートされてないプロパティとして切り捨てているために undefined になるのだと思われる (明確な仕様を見つけられなかった)

Astro から React Component にクラス名を渡す際に class を自動的に className に変換したいという issue も上がっていたが止まっているっぽい。

https://github.com/withastro/astro/issues/448

個人的に class で渡しているものが className という別の名前で受け取れるのは気持ち悪いので、自動変換は不要かなと感じた。 (class で渡して class で受け取れるなら理解できるが)

なので、Astro から React コンポーネントにクラス名を渡したいときは、素直に className を使うのが良い

/src/components/MyComponent.tsx
type MyComponentProps = {
- class?: string;
+ className?: string;
};

- export function MyComponent({ class: className }: MyComponentProps) {
+ export function MyComponent({ className }: MyComponentProps) {
  return (
    <div className={className}>...</div>
  );
}
/src/pages/index.astro
- <MyComponent client:load class="foo" />
+ <MyComponent client:load className="foo" />

まとめ

  • そもそも React では class でクラス名を渡すのは間違った使い方である
  • React の世界では Warning が出るもの className として扱ってくれるが、Astro は React には class でプロパティは渡せないものと判断するので、常に undefined になる
  • 結論: React Component にクラス名を渡すときは className を使う

✌️₍ᐢ.ˬ.ᐢ₎✌️ happy!


https://docs.astro.build/ja/reference/astro-syntax/?utm_source=chatgpt.com

https://github.com/withastro/astro/issues/448

Discussion