前回
概要
新しい、公式サイトは日本語訳がされてなくて不便なので、deeplを使って訳して読んでいくだけ。
感想とかのノイズは極力入れないつもりなので、さらっと見てもらえると
Importing and Exporting Components
コンポーネントの魅力は、その再利用性にあります:他のコンポーネントで構成されたコンポーネントを作成することができます。しかし、より多くのコンポーネントをネストするようになると、それらを別のファイルに分割することが理にかなっていることがよくあります。これにより、ファイルのスキャンが容易になり、より多くの場所でコンポーネントを再利用することができます。
以下のことを学びます。
- ルートコンポーネントファイルとは
- コンポーネントのインポートとエクスポートの方法
- デフォルトと名前付きのインポートおよびエクスポートを使用する場合
- 1つのファイルから複数のコンポーネントをインポートおよびエクスポートする方法
- コンポーネントを複数のファイルに分割する方法
ルートコンポーネントファイル
Your First Componentでは、ProfileコンポーネントとそれをレンダリングするGalleryコンポーネントを作成しました:
function Profile() {
return (
<img
src="https://i.imgur.com/MK3eW3As.jpg"
alt="Katherine Johnson"
/>
);
}
export default function Gallery() {
return (
<section>
<h1>Amazing scientists</h1>
<Profile />
<Profile />
<Profile />
</section>
);
}
これらのファイルは現在、ルートコンポーネントファイル(この例ではApp.jsという名前)に格納されています。Create React Appでは、アプリはsrc/App.jsに存在します。しかし、セットアップによっては、ルートコンポーネントは別のファイルにある可能性があります。Next.jsのようにファイルベースのルーティングを行うフレームワークを使用している場合、ルートコンポーネントはページごとに異なるものになります。
コンポーネントのエクスポートとインポート
将来、ランディング画面を変更して、そこに科学の本のリストを置きたい場合はどうすればいいのでしょうか?あるいは、すべてのプロフィールを別の場所に配置しますか?GalleryとProfileをルートコンポーネントファイルから移動することは理にかなっています。そうすることで、よりモジュール化され、他のファイルでも再利用できるようになります。コンポーネントの移動は、3つのステップで行うことができます:
- コンポーネントを置くために新しいJSファイルを作成します。
- そのファイルから関数コンポーネントをエクスポートします(デフォルトまたは名前付きエクスポートのいずれかを使用します)。
- そのコンポーネントを使用するファイルにインポートします(デフォルトまたは名前付きエクスポートのインポートに対応するテクニックを使用します)。
ここでは、ProfileとGalleryの両方がApp.jsからGallery.jsという新しいファイルに移動しています。これで、App.jsを変更して、Gallery.jsからGalleryをインポートすることができるようになりました:
App.js
import Gallery from './Gallery.js';
export default function App() {
return (
<Gallery />
);
}
Gallery.js
function Profile() {
return (
<img
src="https://i.imgur.com/QIrZWGIs.jpg"
alt="Alan L. Hart"
/>
);
}
export default function Gallery() {
return (
<section>
<h1>Amazing scientists</h1>
<Profile />
<Profile />
<Profile />
</section>
);
}
この例では、2つのコンポーネントファイルに分解されていることに注目してください:
-
Gallery.js:
Gallery.js:Profileコンポーネントを定義しており、同じファイル内でのみ使用され、エクスポートされません。
Galleryコンポーネントは、デフォルトのエクスポートとしてエクスポートされます。 -
App.js
Gallery.jsからのデフォルトのインポートとして、Galleryをインポートします。
デフォルトのエクスポートとして、ルートAppコンポーネントをエクスポートします。
このように拡張子が.jsのままになっているファイルに遭遇することがあります:
import Gallery from './Gallery';
Reactでは「./Gallery.js」または「./Gallery」のどちらかで動作しますが、前者の方がネイティブのESモジュールの動作に近いと言えます。
Default vs named exports
JavaScriptで値をエクスポートするには、デフォルトエクスポートと名前付きエクスポートの2つの主要な方法があります。これまでの例では、デフォルトエクスポートのみを使用してきました。しかし、同じファイル内でどちらか一方、または両方を使用することができます。1つのファイルにデフォルトのエクスポートは1つまでですが、名前付きエクスポートはいくつでも持つことができます。
コンポーネントをどのようにエクスポートするかによって、それをどのようにインポートしなければならないかが決まります。デフォルトのエクスポートを名前付きのエクスポートと同じようにインポートしようとすると、エラーが発生します!この表は、コンポーネントがどのようにエクスポートされたかを追跡するのに役立ちます。
デフォルトのインポートを書くとき、importの後に好きな名前をつけることができます。例えば、代わりにimport Banana from './Button.js' と書いても、同じデフォルトのエクスポートが提供されます。これに対して、名前付きインポートでは、名前が双方で一致しなければならない。そのため、名前付きインポートと呼ばれているのです!
ファイルが1つのコンポーネントだけをエクスポートする場合はデフォルトエクスポートを使用し、複数のコンポーネントと値をエクスポートする場合は名前付きエクスポートを使用することがよくあります。どちらのコーディングスタイルを好むかにかかわらず、コンポーネント関数とそれを含むファイルには、常に意味のある名前を付けてください。export default () => {}のような名前のないコンポーネントは、デバッグを困難にするため、推奨されません。
同一ファイルから複数のコンポーネントをエクスポート、インポートすることができます。
ギャラリーの代わりにProfileを1つだけ表示したい場合はどうすればいいのでしょうか?Profileコンポーネントをエクスポートすることもできます。しかし、Gallery.jsにはすでにデフォルトのエクスポートがあり、デフォルトのエクスポートを2つ持つことはできません。デフォルトのエクスポートを持つ新しいファイルを作成するか、Profileのための名前付きエクスポートを追加することができます。ファイルには、デフォルトのエクスポートは1つしかありませんが、名前付きのエクスポートは多数持つことができます!
デフォルトと名前付きエクスポートの間の潜在的な混乱を減らすために、チームによっては、1つのスタイル(デフォルトまたは名前付き)だけに固執したり、1つのファイルでそれらを混在させないことを選択したりします。あなたにとって最適な方法をとってください!
まず、Gallery.jsから名前付きエクスポート(デフォルトのキーワードなし)を使って、Profileをエクスポートします:
export function Profile() {
// ...
}
そして、Gallery.jsからApp.jsに名前付きimport(中括弧付き)を使ってProfileをインポートします:
import { Profile } from './Gallery.js';
最後に、Appコンポーネントからをレンダリングします:
export default function App() {
return <Profile />;
}
Gallery.jsには、デフォルトのGalleryエクスポートと、名前付きProfileエクスポートの2つのエクスポートが含まれています。App.jsはその両方をインポートしています。この例で、をに編集して、元に戻してみてください:
私の回答
App.js
import Gallery from './Gallery.js';
export default function App() {
return (
<Gallery />
);
}
Gallrery.js
export function Profile() {
return (
<img
src="https://i.imgur.com/QIrZWGIs.jpg"
alt="Alan L. Hart"
/>
);
}
export default function Gallery() {
return (
<section>
<h1>Amazing scientists</h1>
<Profile />
<Profile />
<Profile />
</section>
);
}
今はデフォルトとネームドエクスポートを混ぜて使っていますね:
Gallery.js
ProfileコンポーネントをProfileという名前付きエクスポートとしてエクスポートします。
Galleryコンポーネントは、デフォルトのエクスポートとしてエクスポートされます。
App.js
Gallery.jsからProfileという名前のインポートとしてProfileをインポートします。
GalleryをGallery.jsからデフォルトのインポートとしてインポートします。
ルートAppコンポーネントを、デフォルトのエクスポートとしてエクスポートします。
このページであなたは学んだ:
ルートコンポーネントファイルとは
コンポーネントをインポートおよびエクスポートする方法
デフォルトと名前付きのインポートおよびエクスポートを使用するタイミングと方法
同じファイルから複数のコンポーネントをエクスポートする方法
Try out some challenges
チャレンジ1/1:コンポーネントをさらに分割する
現在、Gallery.jsはProfileとGalleryの両方をエクスポートしていますが、これは少し混乱します。
Profileコンポーネントを独自のProfile.jsに移動し、Appコンポーネントを変更し、との両方を次々にレンダリングするようにします。
Profileのエクスポートは、デフォルトでも名前付きでも構いませんが、App.jsとGallery.jsの両方で対応するインポート構文を使用していることを確認します!上記のディープダイブのテーブルを参照できます:
回答
App.js
import Gallery from './Gallery.js';
import { Profile } from "./Profile.js"
export default function App() {
return (
<div>
<Profile />
<Gallery />
</div>
);
}
Gallrery.js
import { Profile } from "./Profile.js"
export default function Gallery() {
return (
<section>
<h1>Amazing scientists</h1>
<Profile />
<Profile />
<Profile />
</section>
);
}
Profile.js
export function Profile() {
return (
<img
src="https://i.imgur.com/QIrZWGIs.jpg"
alt="Alan L. Hart"
/>
);
}
Writing Markup with JSX
JSXはJavaScriptの構文拡張で、JavaScriptファイル内にHTMLのようなマークアップを記述することができます。コンポーネントを書く方法は他にもありますが、React開発者の多くはJSXの簡潔さを好み、ほとんどのコードベースがJSXを使用しています。
以下のことを学びます。
- Reactがマークアップとレンダリングロジックを混在させる理由
- JSXはHTMLとどう違うのか
- JSXで情報を表示する方法
JSX: Putting markup into JavaScript
Webは、HTML、CSS、JavaScriptで構築されてきました。長年、ウェブ開発者は、コンテンツをHTMLで、デザインをCSSで、ロジックをJavaScriptで、それぞれ別のファイルに保存していました!コンテンツはHTMLでマークアップされ、ページのロジックはJavaScriptで別々に管理されていました:
しかし、Webがよりインタラクティブになるにつれて、ロジックがコンテンツを決定することが多くなりました。HTMLはJavaScriptが担当するようになったのです!そこでReactでは、レンダリングロジックとマークアップを同じ場所、つまりコンポーネントで共存させました。
ボタンのレンダリングロジックとマークアップを一緒にしておくことで、編集のたびにお互いの同期をとることができます。逆に、ボタンのマークアップとサイドバーのマークアップのように、関連性のない詳細は互いに分離されているため、どちらか一方だけを変更しても安全です。
各Reactコンポーネントは、Reactがブラウザにレンダリングするいくつかのマークアップを含むことができるJavaScript関数です。Reactコンポーネントは、そのマークアップを表現するためにJSXと呼ばれる構文拡張を使用します。JSXはHTMLとよく似ていますが、少し厳格で、動的な情報を表示することができます。これを理解するには、いくつかのHTMLマークアップをJSXマークアップに変換するのが最も良い方法です。
JSXとReactは別物です。一緒に使われることが多いのですが、それぞれ独立して使うことができます。JSXは構文拡張で、ReactはJavaScriptライブラリです。
Converting HTML to JSX
ある(完全に有効な)HTMLがあるとします:
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
<li>Invent new traffic lights
<li>Rehearse a movie scene
<li>Improve the spectrum technology
</ul>
そして、それを自分のコンポーネントに入れたいのです:
export default function TodoList() {
return (
// ???
)
}
そのままコピー&ペーストすると、動作しません:
export default function TodoList() {
return (
// This doesn't quite work!
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
<li>Invent new traffic lights
<li>Rehearse a movie scene
<li>Improve the spectrum technology
</ul>
);
}
これは、JSXがHTMLよりも厳格で、いくつかのルールがあるためです!上記のエラーメッセージを読めば、マークアップを修正するためのガイドになりますし、以下のガイドに従うこともできます。
ほとんどの場合、Reactの画面上に表示されるエラーメッセージが、問題の所在を見つけるのに役立ちます。困ったときは読んでみてください!
The Rules of JSX
1. Return a single root element
コンポーネントから複数の要素を返すには、それらを1つの親タグで囲みます。
例えば、<div>
を使用します:
<div>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</div>
マークアップに余分な<div>
を加えたくない場合は、代わりに<>と>を書けばよいのです:
<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</>
この空のタグをフラグメントと呼びます。フラグメントを使えば、ブラウザのHTMLツリーに痕跡を残すことなく、物事をグループ化することができます。
Why do multiple JSX tags need to be wrapped?
JSXはHTMLのように見えますが、その裏側ではプレーンなJavaScriptオブジェクトに変換されています。関数から2つのオブジェクトを返すには、それらを配列にラップする必要があります。このことから、2つのJSXタグを別のタグやフラグメントにラップせずに返すことはできないことがわかります。
2. Close all the tags
JSXでは、タグを明示的に閉じる必要があります。のような自己閉鎖タグは
となり、
このように、Hedy Lamarrの画像とリストの項目が閉じているように見えます:
<>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
/>
<ul>
<li>Invent new traffic lights</li>
<li>Rehearse a movie scene</li>
<li>Improve the spectrum technology</li>
</ul>
</>
3. camelCase all most of the things!
JSXはJavaScriptになり、JSXで書かれた属性はJavaScriptオブジェクトのキーになります。自作コンポーネントでは、その属性を変数に読み替えたいことが多いでしょう。しかし、JavaScriptでは、変数名に制限があります。例えば、変数名にはダッシュが使えなかったり、classのような予約語は使えなかったりします。
そのため、Reactでは、多くのHTMLやSVGの属性がキャメルケースで記述されています。例えば、stroke-widthの代わりにstrokeWidthを使用します。classは予約語なので、Reactでは代わりにclassNameと書き、対応するDOMプロパティにちなんで命名します:
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>
これらの属性はすべて、DOMコンポーネントのpropsのリストで見つけることができます。もし間違っていたとしても、心配はいりません-Reactはブラウザのコンソールに修正可能なメッセージを表示します。
歴史的な理由から、aria-*属性とdata-*属性は、HTMLのようにダッシュで書かれています。
プロヒント:JSXコンバータを使用する
既存のマークアップでこれらの属性をすべて変換するのは面倒なことです!既存のHTMLやSVGをJSXに変換するために、コンバータを使用することをお勧めします。コンバータは実際にはとても便利ですが、自分で快適にJSXを書けるように、何が起こっているかを理解する価値はあります。
まとめ
JSXの存在理由とコンポーネントでの使用方法についてご理解いただけたと思います:
Reactコンポーネントは、レンダリングロジックとマークアップが関連しているため、レンダリングロジックをマークアップと一緒にまとめています。
JSXはHTMLに似ていますが、少し違いがあります。必要であればコンバータを使うことができます。
エラーメッセージは、マークアップを修正するための正しい方向を示してくれることが多いです。
Try out some challenges
チャレンジ1/1:あるHTMLをJSXに変換する
このHTMLはコンポーネントに貼り付けられましたが、有効なJSXではありません。修正する:
私の回答
export default function Bio() {
return (
<>
<div className="intro">
<h1>Welcome to my website!</h1>
</div>
<p className="summary">
You can find my thoughts here.
<br/>
<b>And<i>pictures</i></b> of scientists!
</p>
</>
);
}
次回