diff --git a/.gitignore b/.gitignore index 0c34a7d22..1ed7758f7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /build .DS_Store dist +*.sw[op] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..290555455 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing + +## Japanese Version + +* Changes to the Japanese Version are approved by @38elements. +* For easy review, place each sentence on a new line. +* Cosmetic changes are not accepted. diff --git a/content/ja/404.md b/content/ja/404.md new file mode 100755 index 000000000..57dc23e30 --- /dev/null +++ b/content/ja/404.md @@ -0,0 +1,5 @@ +# エラー + +おっと、このページは消えたみたいです。 + +[ホーム](/)に向かいましょう。 diff --git a/content/ja/about/browser-support.md b/content/ja/about/browser-support.md new file mode 100755 index 000000000..6e38c4c71 --- /dev/null +++ b/content/ja/about/browser-support.md @@ -0,0 +1,15 @@ +--- +name: ブラウザのサポート +permalink: '/about/browser-support' +description: "Preactはそのままですべてのモダンブラウザ(Chrome, Firefox, Safari, Edge)とIE11をサポートします。" +--- + +# ブラウザのサポート + +Preactはモダンブラウザ(Chrome, Firefox, Safari, Edge)とIE11をサポートします。polyfillを追加することなくそのままで動作します。 + +
+ + Browser List + +
diff --git a/content/ja/about/project-goals.md b/content/ja/about/project-goals.md new file mode 100755 index 000000000..1132c1de8 --- /dev/null +++ b/content/ja/about/project-goals.md @@ -0,0 +1,29 @@ +--- +name: プロジェクトの目的 +permalink: '/about/project-goals' +description: "Preactプロジェクトの目的について詳しく知る" +--- + +# Preactの目的 + +## 目的 + +Preactは以下の目的を達成することを目指しています。 + +- **パフォーマンス** 高速で効率的なレンダリング +- **サイズ** 軽量で小さいサイズ _(約3.5kB)_ +- **効率** 効率的なメモリの使用法 _(GCスラッシングの回避)_ +- **分かりやすさ** 数時間以内にコードベースを理解することができる +- **互換性** PreactはReact APIとほとんど互換性があることを目指します。 [preact/compat]は可能な限りReactとの互換性を実現しようとしています。 + +## 目的に含まれない物 + +Reactの機能の一部は意図的にPreactでは提供されていません。 +なぜなら、上記のプロジェクトの目的を達成する上で障害となる機能やPreactのコア機能の範囲に収まらないからです。 + +意図的な[Reactとの違い](/guide/v10/differences-to-react): +- `PropTypes`は、外部のライブラリを使用できるので、本体にはいれていません。 +- `Children`は標準のArrayに置き換えることができます。 +- `Synthetic Events`はPreactがIE8のような古いブラウザに対応しないのでサポートされません。 + +[preact/compat]: /guide/v10/switching-to-preact diff --git a/content/ja/about/we-are-using.md b/content/ja/about/we-are-using.md new file mode 100755 index 000000000..26e02b4b8 --- /dev/null +++ b/content/ja/about/we-are-using.md @@ -0,0 +1,15 @@ +--- +name: Preactを使っている企業 +title: 誰がPreactを使っていますか? +permalink: '/about/we-are-using' +description: 'Preactを使っている企業' +--- + +Preactはオープンソースから大きな多国籍企業まで幅広いウェブサイトに使われています。 +以下は一般公開しているプロジェクトでPreactを使用している組織の例です。 + +あなたの会社はPreactを使っていますか? それなら、[リストに加えましょう!](https://github.com/preactjs/preact-www/blob/master/src/components/we-are-using/index.js) + +
+ +
diff --git a/content/ja/cli.md b/content/ja/cli.md new file mode 100644 index 000000000..9738866f0 --- /dev/null +++ b/content/ja/cli.md @@ -0,0 +1,37 @@ +--- +name: CLI +permalink: '/cli' +description: 'Preact CLIの説明' +--- + +# Preact CLI + +[Preact CLI](https://github.com/preactjs/preact-cli/)を使えばたった数秒で超高速のPreact PWAの開発を始めることができます。 + +Preact CLIは新しいプロジェクトを始める際の手間を省くことができます。そして、理解しやすい小さいプロジェクト構成で即座に開発を進めることができます。 +Preact CLIはWebpack、Babel、Terserなど定番のオープンソースのツールで構成されています。そして、それを設定なしで使うことができます。 +そして、ホットリロードからクリティカルCSSのインライン化まですべてが最適になるように用意されます。 + +Preact CLIに沿って開発すればハイパフォーマンスなアプリケーションを開発することができます。 +Preact CLIが作成したできたてのプロジェクトのJavaScriptはProductionビルドでわずか4.5kBです。 +これは遅い端末と遅いネットワークでさえ3秒以内で操作可能になります。 + +## 機能 + +Preact CLIは以下の機能をデフォルトで使うことができます。 + +- デフォルトで100/100 Lighthouseスコア([証拠](https://googlechrome.github.io/lighthouse/viewer/?gist=142af6838482417af741d966e7804346)). +- 完全自動なrouteごとのcode-splitting(コード分割) +- asyncを付けるだけでcode-splittingします +- JavaScriptの変更を検知しオートリロードする +- Workboxベースのオフラインキャッシュを可能にするService Workerの自動生成 +- 効率的なロードを実現するPRPLパターンのサポート +- 設定なしでプリレンダリング/サーバサイドレンダリングで生成されたDOMのhydrationの実行 +- Autoprefixerを適用したCSS Modules、LESS、Sass、Stylusのサポート +- bundle/chunkサイズを監視するトラッキング機能 +- 自動的なアプリケーションのマウント、デバックヘルパー、Hot Module Replacement +- Preact +- preact-router +- 必要に応じてロードされる1.5kbのfetchとPromiseのpolyfill + +詳しく知りたい場合は[はじめに](/cli/getting-started)を読んでください。 diff --git a/content/ja/cli/getting-started.md b/content/ja/cli/getting-started.md new file mode 100644 index 000000000..88b00a4d8 --- /dev/null +++ b/content/ja/cli/getting-started.md @@ -0,0 +1,96 @@ +--- +name: はじめに +permalink: '/cli/getting-started' +description: 'Preact CLIを始める' +--- + +# はじめに + +最初にPreact CLIを[npm](https://npmjs.com/package/preact-cli)からインストールします。 + +```shell +npm i -g preact-cli +``` + +これで`preact`コマンドがグローバルにインストールされます。 +これを使用して新しいプロジェクトを作成していきます。 + +## プロジェクトの作成 + +### テンプレート + +プロジェクトを作成するために以下の公式テンプレートがあります。 + +- **Default** + +ほとんどのアプリケーションには、このテンプレートが適しています。 +これには`preact-router`とデフォルトで仮のrouteが付属しています。そして、routeベースのcode-splittingになっています。 + +- **Simple** + +"Hello, World"アプリケーションから始めるような骨組だけのテンプレートです。 +自分でツールを選択したい場合や既に構成が決まっている場合はこれで始めると良いでしょう。 + +- **Material** + +このテンプレートには[preact-material-components](https://material.preactjs.com)が付属していて、さらに例として小さいアプリケーションが用意されているので手軽に開発を始めることができます。 + +- **Netlify CMS** + +ブログを始めたいと思っていますか?ここに良いものがあります。 +このテンプレートは[Netlify CMS](https://www.netlifycms.org/)を使って編集することができるシンプルでエレガントなブログを提供します。 + +これらのテンプレートを使うには以下のように`preact create`コマンドでテンプレートを指定して新しいプロジェクトを作成します。 + +```sh +preact create +``` + +これでプロジェクトが作成されました。 +以下のように、新たに作成されたディレクトリに`cd`で移動します。そして、開発サーバを起動します。 + +```sh +cd +npm run dev +``` + +エディタを開いて編集を始めましょう。 +ほとんどのテンプレートでは`start/index.js`か`src/components/app/index.js`から編集し始めると良いでしょう。 + +## Productionビルド + +`npm run build`コマンドはアプリケーションをProductionビルドします。そして、それをプロジェクトルートの下の`build`ディレクトリに配置します。 + +Productionビルドはフラグをセットすることによって必要に応じて微調整することができます。フラグの完全なリストは[こちら](https://github.com/preactjs/preact-cli#preact-build)を見てください。 + +**使用例** + +例えば、以下のコマンドでは[webpack analyzer](https://chrisbateman.github.io/webpack-visualizer/)用のwebpackのアセットのJSONを生成します。 + +```sh +preact build --json +``` + +## index.htmlを編集する + +`preact-cli`によって生成されるマークアップのメタタグやカスタムスクリプトやフォントを編集したい場合は、`src/template.html`を編集します。 +この機能は`preact-cli` v3で利用可能です。レンダリングに[EJS](https://ejs.co/)を使っています。 + +```html + + + + + <% preact.title %> + + + + <% preact.headEnd %> + + + <% preact.bodyEnd %> + + +``` + +> 古いバージョンからアップグレードした時は`src/template.html`を作成することで次回以降、アプリケーションをビルドした時や開発サーバを起動した時にそれが使われます。 diff --git a/content/ja/cli/pre-rendering.md b/content/ja/cli/pre-rendering.md new file mode 100644 index 000000000..92ddd4c7d --- /dev/null +++ b/content/ja/cli/pre-rendering.md @@ -0,0 +1,170 @@ +--- +name: 'Preact CLI: Pre-rendering' +permalink: '/cli/pre-rendering' +description: 'Preact CLIを使ってページを自動的にプリレンダリング(Pre-rendering)する' +--- + +# ページをプリレンダリング(Pre-rendering)する + +Preact CLIは自動的にページをプリレンダリング(Pre-rendering)して静的なHTMLに変換します。これによって、高速なロードが可能になります。 + +Productionビルドする場合、Preact CLIはコンポーネントをレンダリングして、その結果を静的なHTMLとして保存します。 +これによって、サイトの閲覧者はJavaScriptのロードが完了する前でも、すぐにプリレンダリングされたHTMLを見ることができます。 + +> **⚠️ 注意:** プリレンダリングはNodeJS環境で実行されるため、ほとんどのWeb APIは使用できません。NodeJS環境かどうか判断するには`if (typeof window !== 'undefined')`のようなコードを使います。 + +## URLとカスタムデータの設定 + +デフォルトでは`/`にrouteされたページのみプリレンダリングします。 +他のURL(route)を追加するには、以下のような`prerender-urls.json`ファイルを作成する必要があります。 +このファイルを使用して、各URLの``コンポーネントのpropsに追加のデータを渡すことも出来ます。 + +```json +[ + { + "url": "/", // 必須 + "title": "All About Dogs", + "breeds": ["Shiba", "Golden", "Husky"] + }, + { + "url": "/breeds/shiba", // 必須 + "title": "Shibas!", + "photo": "/assets/shiba.jpg" + } +] +``` + +### 動的プリレンダリング + +`prerender-urls.json`だけでなく、JavaScriptファイルを使用して同様の設定を行うことができます。 +そのJavaScriptファイルではプリレンダリングで使用する設定データを返す関数を定義する必要があります。 +その関数はPreact CLIで実行されます。 + +動的プリレンダリングを行う場合は、以下のようにPreact CLIにJavaScriptファイルを指定する必要があります。 + +`preact build --prerenderUrls ./prerender-urls.js` + +例えば、`prerender-urls.js`は以下のようにします。 + +```js +const breeds = ["Shiba", "Golden", "Husky"]; + +module.exports = function() { + return [ + { + url: "/", + title: "All About Dogs", + breeds + }, + { + url: "/breeds/shiba", + title: "Shibas!", + photo: "/assets/shiba.jpg" + } + ]; +}; +``` + +#### マークアップ内でプリレンダリングの設定データを使う + +以上で設定したデータは`html`ファイルを生成する際に使用する`src/template.html`ファイル内で使用することができます。 +このデータを使ってmetaタグ等の有用なデータをすべてのページに加えることができます。 +値を使用するにはマークアップ内で`htmlWebpackPlugin.options.CLI_DATA.preRenderData.`を使います。 + +```html + + + + + +``` + +### 外部のデータソースを使う + +Preact CLIのカスタムプリレンダリングを使用することでCMSのような外部のデータソースと連携することができます。 +CMSからデータを取得して、URLごとにプリレンダリングするには、以下のように`prerender-urls.js`ファイルからasync関数を`export`します。 + +```js +module.exports = async function() { + const response = await fetch('https://cms.example.com/pages/'); + const pages = await response.json(); + return pages.map(page => ({ + url: page.url, + title: page.title, + meta: page.meta, + data: page.data + })); +}; +``` + +## プリレンダリング用のデータを使う + +プリレンダリングで生成されたページには、以下のようにプリレンダリング用のデータがインラインスクリプトとして含まれます。 + +```html + +``` + +このプリレンダリング用のデータを使って"rehydrate"することができます。 +これは、特にReduxのようなステート管理ソリューションやGraphQLを使う場合に役立ちます。 +HTMLに出力されたJSONデータは常に`url`キーを含みます。これはrouteされたページをhydrateすることに役立ちます。 + +> **💡 メモ:** ユーザが最初にアプリケーションにアクセスした時、ダウンロードサイズを節約するためにページのマークアップにはそのrouteのプリレンダリングのデータのみが含まれます。ユーザがブラウザを操作して他のrouteに遷移した場合はマークアップにはそのページのプリレンダリング用のデータはありません。そのrouteのプリレンダリングのデータを取得したい場合は`//preact_prerender_data.json`にリクエストをしてください。Preact CLIはビルド時に、プリレンダリングされた各ページと同じディレクトリに`preact_prerender_data.json`ファイルを生成します。 + +### `@preact/prerender-data-provider`を使う + +Preact CLIでプリレンダリングデータを簡単に扱うために、hydrationとデータの取得を行うラッパーライブラリを用意しています。 +このラッパーライブラリは、URLとプリレンダリングデータの`url`が一致する場合は、インラインスクリプトタグからプリレンダリングデータを取得します。 +ユーザがブラウザ上でページ遷移した場合など、URLとプリレンダリングデータの`url`が一致しない場合は、サーバにリクエストを行ってプリレンダリングデータを取得します。 + +最初に以下のようにnpmからライブラリをインストールします。 + +`npm i -D @preact/prerender-data-provider` + +これでライブラリをインストールできました。 +次にAppコンポーネント(`components/app.js`)にそれを`import`して使います。 + +```jsx +import { Provider } from '@preact/prerender-data-provider'; + +export default class App extends Component { + // ... + render(props) { + return ( + + // アプリケーションをここに置きます。 + + ) + } +} +``` + +これで、routeされているコンポーネントは`prerender-data-provider`を通じてプリレンダリングのデータにアクセスすることが可能になりました。 + +```jsx +import { usePrerenderData } from '@preact/prerender-data-provider'; + +export default function MyRoute(props) { + + // usePrerenderData(props, false)とするとこのフックが自動的にデータ取得リクエストを送信することを無効にします。 + const [data, loading, error] = usePrerenderData(props); + + if (loading) return

Loading...

; + + if (error) return

Error: {error}

; + + return ( +
+ // データはここで使う。 +
+ ); +} +``` + +`usePrerenderData`の第2引数にfalseを渡すと`preact_prerender_data.json`を自動的に取得しません。 +`usePrerenderData`フックと同じ役割を持つ``もあります。 diff --git a/content/ja/cli/service-worker.md b/content/ja/cli/service-worker.md new file mode 100644 index 000000000..760270da5 --- /dev/null +++ b/content/ja/cli/service-worker.md @@ -0,0 +1,138 @@ +--- +name: Service Worker +permalink: '/cli/service-workers' +description: Service Worker +--- + +# Preact CLIでオフラインに対応する + +Preact CLIはオフラインで使用するために自動的にアプリケーションのコードとプリレンダリングのデータをキャッシュ可能にします。 + +Preact CLI 3は[Workbox](https://developers.google.com/web/tools/workbox)を内蔵するようになりました。 +Workboxは[InjectManifest plugin](https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin#injectmanifest_plugin_2)を使って幅広い用途をカバーする柔軟なService Workerを生成します。 + +> **注意:** Preact CLIは画面遷移に[network-first](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook#network-falling-back-to-cache)アプローチを採用しているので、ユーザはオフラインの時を除いて常に最新の内容を見ることができます。 + +## カスタムService Workerを追加する + +Preact CLIを使うと、なにもコードを書かなくても、アプリケーションのProductionビルド時にService Workerのコードが自動生成されます。 +このService Workerをカスタマイズするためには、プロジェクトの`sw.js`ファイルを変更します。Preact CLIは、このカスタマイズに使用するためのAPIをいくつか提供しています。 + +**1. `src/`ディレクトリ内に`sw.js`ファイルを作成する** + +```sh +package.json +src/ + index.js + sw.js +``` + +**2. Preact CLIのService Worker用ライブラリである`preact-cli/sw`を`import`する** + +```js +import { getFiles, setupPrecaching, setupRouting } from 'preact-cli/sw'; +``` + +**3. オフラインルーティングを有効にする** + +以下のようにしてオフライン時のnetwork-firstフォールバックの設定をします。 +カスタムフォールバックを設定したい場合はこれをスキップしてください。 + +```js +import { getFiles, setupPrecaching, setupRouting } from 'preact-cli/sw'; + +setupRouting(); +``` + +**4. リソースのプリキャッシュを有効にする** + +`getFiles()`はオフライン時に使用するためにキャッシュしておくべきURLの配列を返します。この配列はビルド時に生成することができます。 +これらのURLを`setupPrecaching()`に渡すことで`setupRouting()`が使用するキャッシュにダウンロードして保存されます。 + +```js +import { getFiles, setupPrecaching, setupRouting } from 'preact-cli/sw'; + +setupRouting(); + +const urlsToCache = getFiles(); +setupPrecaching(urlsToCache); +``` + +**4.1 その他のアセットをプリキャッシュマニフェストに追加する** + +プリキャッシュマニフェストに何か追加したい場合は以下の例のように`urlsToCache`にエントリー({url, revision})を追加します。 + +```js +import { getFiles, setupPrecaching, setupRouting } from 'preact-cli/sw'; + +setupRouting(); + +const urlsToCache = getFiles(); +urlsToCache.push({url: '/favicon.ico', revision: null}); + +setupPrecaching(urlsToCache); +``` + +> 上記のrevisionはリソースの変更を検知しキャッシュを無効にするために使われます。URLに判別可能な情報(例えばハッシュ)が含まれる場合は`null`を渡して構いません。 + +**5. カスタムService Workerのロジックを加える** + +これでPreact CLIにカスタムService Workerを追加することができました。 +必要に応じてプリキャッシュするURLをカスタマイズしたり[push notificationsをセットすることができます。](https://developers.google.com/web/ilt/pwa/introduction-to-push-notifications) + +## ランタイムキャッシュに他のrouteを追加する + +他のrouteやAPIコールをランタイムキャッシュするには、最初に[上記のステップ](#adding-a-custom-service-worker)を参考にしてカスタム`sw.js`を作成します。 +それから、Workbox APIを使ってカスタムService Workerを登録します。 + +```js +import { registerRoute } from 'workbox-routing'; +import { NetworkOnly } from 'workbox-strategies'; + +registerRoute( + ({url, event}) => { + return (url.pathname === '/special/url'); + }, + new NetworkOnly() // もしくはCacheFirst/CacheOnly/StaleWhileRevalidate +); +``` + +上記の例の`networkOnly`はService Workerが`/special/url`をキャッシュしないことを意味します。 + +> **メモ:** カスタムルーティングのコードは`setupRouting()`の前に置く必要があります。 + +## Service Workerで他のWorkboxのモジュールを使う + +Preact CLIは[injectManifestPlugin](https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-webpack-plugin.InjectManifest)を使用して、Service Workerをコンパイルします。 +他のWorkbox[モジュール](https://github.com/GoogleChrome/workbox/tree/v6/packages)を使用するためには、それらをNPMからインストールして`src/sw.js`に`import`する必要があります。 + +**例: Background syncを追加する** + +以下のコードを`sw.js`ファイルに加えるとします。 +このコードは[Workbox Background Sync](https://developers.google.com/web/tools/workbox/modules/workbox-background-sync)を使って、オフラインの時に失敗したリクエストを再度送信します。 + +```js +import { getFiles, setupPrecaching, setupRouting } from 'preact-cli/sw'; +import { BackgroundSyncPlugin } from 'workbox-background-sync'; +import { registerRoute } from 'workbox-routing'; +import { NetworkOnly } from 'workbox-strategies'; + +const bgSyncPlugin = new BackgroundSyncPlugin('apiRequests', { + maxRetentionTime: 60 +}); + +// 失敗した/api/**.jsonに対するPOSTリクエストをリトライする。 +registerRoute( + /\/api\/.*\/.*\.json/, + new NetworkOnly({ + plugins: [bgSyncPlugin] + }), + 'POST' +); + +/** Preact CLIをセットする */ +setupRouting(); + +const urlsToCache = getFiles(); +setupPrecaching(urlsToCache); +``` diff --git a/content/ja/guide/v10/api-reference.md b/content/ja/guide/v10/api-reference.md new file mode 100644 index 000000000..c58b4fa32 --- /dev/null +++ b/content/ja/guide/v10/api-reference.md @@ -0,0 +1,242 @@ +--- +name: APIリファレンス +description: 'Preactモジュールでエクスポートされているすべての関数について詳しく学びましょう。' +--- + +# APIリファレンス + +このページはPreactで提供されているすべての関数の概要を記載します。 + +--- + +
+ +--- + +## Component + +`Component`はステートフルなPreactコンポーネントを作成するために拡張して使用するベースクラスです。 +コンポーネントは直接インスタンス化するのではなく、レンダラーによって管理され必要に応じて生成されます。 + +```js +import { Component } from 'preact'; + +class MyComponent extends Component { + // (see below) +} +``` + +### Component.render(props, state) + +すべてのコンポーネントは`render()`関数を持つ必要があります。`render()`はコンポーネントの現在の`porps`と`state`が渡されます。そして、仮想DOM要素、配列、`null`を返す必要があります。 + +```jsx +import { Component } from 'preact'; + +class MyComponent extends Component { + render(props, state) { + // propsはthis.propsと同じ + // stateはthis.stateと同じ + + return

Hello, {props.name}!

; + } +} +``` + +コンポーネントとその使い方を詳しく知りたい場合は[コンポーネントのドキュメント](/guide/v10/components)をチェックしてください。 + +## render() + +`render(virtualDom, containerNode, [replaceNode])` + +仮想DOM要素を親DOM要素である`containerNode`内にレンダリングします。戻り値はありません。 + +```jsx +// DOMツリーがレンダリングされる前 +//
+ +import { render } from 'preact'; + +const Foo = () =>
foo
; + +render(, document.getElementById('container')); + +// レンダリングされた後 +//
+//
foo
+//
+``` + +オプションの`replaceNode`パラメータ指定する場合は、`containerNode`の子要素でなければなりません。 +レンダリングの開始地点を推測する代わりに、Preactは差分アルゴリズムを使用して渡された要素(`replaceNode`)を更新または置換します。 +詳しくは[render()は常にコンテナ内にレンダリングした要素を上書きする](/guide/v10/upgrade-guide)を確認してください。 + +```jsx +// DOMツリーがレンダリングされる前 +//
+//
bar
+//
foo
+//
+ +import { render } from 'preact'; + +const Foo = () =>
BAR
; + +render( + , + document.getElementById('container'), + document.getElementById('target') +); + +// レンダリングされた後 +//
+//
bar
+//
BAR
+//
+``` + +第1引数は仮想DOMでなければなりません。その仮想DOMはコンポーネントもしくはHTML要素を表す必要があります。 +コンポーネントを渡す際は以下のように直接インスタンス化するのではなく必ずPreactにインスタンス化を任せてください。直接インスタンス化すると予期しない方法で止まります。 + +```jsx +const App = () =>
foo
; + +// コンポーネントを直接指定することはフックと更新順序を破壊するのでしないでください。 +render(App(), rootElement); // エラー +render(App, rootElement); // エラー + +// コンポーネントをh()もしくはJSXで渡すと正常に動作します。 +render(h(App), rootElement); // 成功 +render(, rootElement); // 成功 +``` + +## hydrate() + +プリレンダリングもしくはサーバサイドレンダリングによって既にアプリケーションをHTMLに出力している場合、ブラウザでのロード時にほとんどのレンダリング処理をバイパスします。 +これは`render()`を`hydrate()`に置き換えることで有効になります。これは大半の差分処理を省略しつつ、イベントリスナをセットしコンポーネントツリーを構築します。 +これは[プリレンダリング](/cli/pre-rendering)もしくは[サーバサイドレンダリング](/guide/v10/server-side-rendering)と連携した場合のみ動作します。 + + +```jsx +import { hydrate } from 'preact'; + +const Foo = () =>
foo
; +hydrate(, document.getElementById('container')); +``` + +## h() / createElement() + +`h(type, props, ...children)` + +与えられた`props`を持つ仮想DOM要素を返します。 +仮想DOM要素はアプリケーションのUIの階層構造に所属するノードを表す軽量なデータです。 +仮想DOM要素の実態は基本的には`{ type, props }`という形式のオブジェクトです。 + +`type`と`props`を除く残りのパラメーターは配列である`children`に格納されます。 +`type`と`props`を除く残りの引数は、仮想DOM要素の`children`プロパティに格納されます。 +`children`は次のどれかです。 + +- スカラー値 (`string`、`number`、`boolean`、`null`、`undefined`等) +- ネストされた仮想DOM要素 +- 上記の要素を持つ配列 + +```js +import { h } from 'preact'; + +h('div', { id: 'foo' }, 'Hello!'); +//
Hello!
+ +h('div', { id: 'foo' }, 'Hello', null, ['Preact!']); +//
Hello Preact!
+ +h( + 'div', + { id: 'foo' }, + h('span', null, 'Hello!') +); +//
Hello!
+``` + +## toChildArray + +このヘルパー関数は`props.children`の値の構造やネストに関係なくそれをフラット化します。 +`props.children`が既に配列の場合、コピーを返します。 +この関数は`props.children`が必ず配列とは限らない場合に役に立ちます。それはJSXの静的な処理と動的な処理の組み合わせで発生することがあります。 + +仮想DOM要素が子要素を1つ持つ場合、`props.children`は直接子要素を参照します。 +複数の子要素を持つ場合、`props.children`は常に配列になります。 +`toChildArray`を使用するとすべてのケースを一貫して処理することができます。 + +```jsx +import { toChildArray } from 'preact'; + +function Foo(props) { + const count = toChildArray(props.children).length; + return
I have {count} children
; +} + +// props.childrenは"bar" +render( + bar, + container +); + +// props.childrenは[

A

,

B

] +render( + +

A

+

B

+
, + container +); +``` + +## cloneElement + +`cloneElement(virtualElement, props, ...children)` + +この関数は仮想DOM要素の浅い(shallow)コピーを作成します。 +要素の`props`を追加する際や上書きする際によく使用します。 + +```jsx +function Linkout(props) { + // target="_blank"をリンクに追加 + return cloneElement(props.children, { target: '_blank' }); +} +render(home); +// home +``` + +## createContext + +[Context documentation](/guide/v10/context#createcontext)のcreateContextの項目を見てください。 + +## createRef + +レンダリングで生成されたコンポーネントや要素の参照を取得する際に使用します。 + +詳細は[リファレンスのドキュメント](/guide/v10/refs#createref)を見てください。 + +## Fragment + +子要素を持つことができるが、DOM要素としてレンダリングされない特殊なコンポーネントです。 +`Fragment`はDOMコンテナーのラップなしで兄弟関係にある複数の子要素を返すことを可能にします。 + +```jsx +import { Fragment, render } from 'preact'; + +render( + +
A
+
B
+
C
+
, + document.getElementById('container') +); +// レンダリングした結果 +//
; + +// レンダリング結果:
My name is John Doe.
+render(App, document.body); +``` + +> 注意: 以前のバージョンでは「ステートレスコンポーネント」として知られていましたが、現在は[フックを使用すること](/guide/v10/hooks)でステートを持つことができます。 + +## クラスコンポーネント + +クラスコンポーネントはステートとライフサイクルメソッドを持つことができます。 +ライフサイクルメソッドは特別なメソッドです。例えば、コンポーネントがDOMにマウントされた時やDOMから削除された時に実行されます。 + +以下はという現在の時刻を表示するシンプルなクラスコンポーネントです。 + +```jsx +class Clock extends Component { + + constructor() { + super(); + this.state = { time: Date.now() }; + } + + // ライフサイクルメソッド: コンポーネントがDOMにマウントされた時に実行 + componentDidMount() { + // 1秒ごとに時刻を更新 + this.timer = setInterval(() => { + this.setState({ time: Date.now() }); + }, 1000); + } + + // ライフサイクルメソッド: コンポーネントがDOMから削除される直前に実行 + componentWillUnmount() { + // レンダリングが不可能なので停止 + clearInterval(this.timer); + } + + render() { + let time = new Date(this.state.time).toLocaleTimeString(); + return {time}; + } +} +``` + +### ライフサイクルメソッド + +現在の時計の時刻を1秒ごとに更新するためにいつ``がDOMにマウントされるかを知る必要があります。 +もし、HTML5 Custom Elementsを使ったことがあれば、_それはHTML5 Custom Elementsのライフサイクルメソッドである`attachedCallback`と`detachedCallback`に似ています。_ +Preactはコンポーネントに以下のライフサイクルメソッドが定義されている場合、それを実行します。 + +| ライフサイクルメソッド | 実行されるタイミング | +|-----------------------------|--------------------------------------------------| +| `componentWillMount()` | (非推奨) コンポーネントがDOMにマウントされる前 | +| `componentDidMount()` | コンポーネントがDOMにマウントされた後 | +| `componentWillUnmount()` | DOMから削除される前 | +| `componentWillReceiveProps(nextProps, nextState)` | (非推奨) 新しいpropsを受け取る前 | +| `getDerivedStateFromProps(nextProps)` | `shouldComponentUpdate`の直前。注意して使って下さい。 | +| `shouldComponentUpdate(nextProps, nextState)` | `render()`の前。`false`を返したらrenderをスキップする。 | +| `componentWillUpdate(nextProps, nextState)` | (非推奨) `render()`の前。 | +| `getSnapshotBeforeUpdate(prevProps, prevState)` | `render()`が実行される直前。戻り値は`componentDidUpdate`に渡される。 | +| `componentDidUpdate(prevProps, prevState, snapshot)` | `render()`の後 | + +> [この図](https://twitter.com/dan_abramov/status/981712092611989509)を見てこれらが互いにどのように関係しているのか確認しましょう。 + +#### componentDidCatch + +注目すべきライフサイクルメソッドが1つあります。それは`componentDidCatch`です。 +レンダリング中に発生したエラーを扱うことができる点が特別です。 +それにはライフサイクルフック中に発生したエラーも含まれます。 +しかし、例えば、`fetch()`を実行した後の非同期にスローされるようなエラーは扱うことができません。 + +エラーが発生した場合、このライフサイクルメソッドを使ってエラーの対応をしたりエラーメッセージを表示したり代替のコンテンツを表示することができます。 + +```jsx +class Catcher extends Component { + + constructor() { + super(); + this.state = { errored: false }; + } + + componentDidCatch(error) { + this.setState({ errored: true }); + } + + render(props, state) { + if (state.errored) { + return

Something went badly wrong

; + } + return props.children; + } +} +``` + +## Fragments + +`Fragment`はrender関数と関数コンポーネントが一度に複数の要素を返すことを可能にします。 +`Fragment`はコンポーネントが単一のルート要素を持たなければならないというJSXの制限を解決します。 +リスト、テーブル、CSSのflexboxなど、余分な中間要素をいれてしまうと表示が崩れてしまう場合によく使われます。 + +```jsx +import { Fragment, render } from 'preact'; + +function TodoItems() { + return ( + +
  • A
  • +
  • B
  • +
  • C
  • +
    + ) +} + +const App = ( +
      + +
    • D
    • +
    +); + +render(App, container); +// レンダリング結果: +//
      +//
    • A
    • +//
    • B
    • +//
    • C
    • +//
    • D
    • +//
    +``` + +最新のトランスパイラのほとんどは`Fragments`の短いシンタックスを使うことができ、こちらのほうが一般的です。 + +```jsx +const Foo = foo; +// 上記は下記と同じ +const Bar = <>foo; +``` + +render関数と関数コンポーネントは配列を返すこともできます。 + +```jsx +function Columns() { + return [ + Hello, + World + ]; +} +``` + +ループ中に`Fragments`を生成する場合は`key`属性を付与することを忘れないで下さい。 + +```jsx +function Glossary(props) { + return ( +
    + {props.items.map(item => ( + // キーがない場合、Preactは再レンダリング時、変更された要素を特定できません。 + +
    {item.term}
    +
    {item.description}
    +
    + ))} +
    + ); +} +``` diff --git a/content/ja/guide/v10/context.md b/content/ja/guide/v10/context.md new file mode 100644 index 000000000..34bd350a4 --- /dev/null +++ b/content/ja/guide/v10/context.md @@ -0,0 +1,88 @@ +--- +name: コンテキスト(Context) +description: 'コンテキストは間にあるコンポーネントを飛ばしてpropsを渡すことができます。このドキュメントは新しいAPIと古いAPIの両方を説明します。' +--- + +# コンテキスト(Context) + +コンテキスト(Context)は深い階層にある子コンポーネントにその間にあるすべてのコンポーネントの`props`を介することなく値を渡すことを可能にします。一般的なユースケースはテーマの設定です。端的に言うとコンテキストはPreactでPub-Subスタイルの更新を行う方法だと考えることができます。 + +コンテキストには2通りの使用方法があります。それは新しい`createContext`APIと古いコンテキストAPIです。 +この2つの違いは古いAPIでは、間にあるコンポーネントが`shouldComponentUpdate`でレンダリングを中止した場合、その子コンポーネントの更新処理が実行されないことです。 +これを理由に、常に`createContext`を使うことを強く推奨します。 + +--- + +
    + +--- + +## createContext + +最初にコンポーネント間を通過することができるコンテキストオブジェクを生成する必要があります。 +これは`createContext(initialValue)`関数で行います。 +`createContext(initialValue)`はコンテキストの値をセットするために使われる`Provider`コンポーネントとコンテキストから値を受け取る`Comsumer`コンポーネントを返します。 + +```jsx +const Theme = createContext('light'); + +function ThemedButton(props) { + return ( + + {theme => { + return ; + }} + + ); +} + +function App() { + return ( + + + + + + ); +} +``` + +> [useContext](/guide/v10/hooks#context)フックを使うと簡単にコンテキストを扱うことができます。 + +## 古いコンテキストAPI + +古いコンテキストAPIは主に後方互換性のために存在しており、現在は`createContext`APIに置き換えられました。 +古いコンテキストAPIはコンテキストの値を提供するコンポーネントと受け取るコンポーネントの間にあるコンポーネントが`shouldComponentUpdate`で`false`を返した場合、受け取るコンポーネントの更新処理が実行されない既知の問題があります。 +それにもかかわらず使う必要があるなら読み続けてください。 + +コンポーネントがコンテキストを介してデータを子コンポーネントに渡すには、コンポーネントは`getChildContext`メソッドを持つ必要があります。 +`getChildContext`メソッドでは、コンテキストに新しく格納したい値を返します。 +コンテキストには関数コンポーネントの第2引数もしくはクラスコンポーネントの`this.context`でアクセスすることができます。 + +```jsx +function ThemedButton(props, context) { + return ( + ; + ); +} + +class App extends Component { + getChildContext() { + return { + theme: 'light' + } + } + + render() { + return ( +
    + + + +
    + ); + } +} +``` diff --git a/content/ja/guide/v10/debugging.md b/content/ja/guide/v10/debugging.md new file mode 100644 index 000000000..a2491fa12 --- /dev/null +++ b/content/ja/guide/v10/debugging.md @@ -0,0 +1,229 @@ +--- +name: Preactアプリケーションのデバッグ +description: '問題が起きたときにPreactアプリケーションをデバッグする方法' +--- + +# Preactアプリケーションのデバッグ + +Preactにはデバックを容易にするツールが付属しています。それらは`preact/debug`にパッケージングされています。そして、`preact/debug`を`import`することで使うことができます。 + +それらにはChromeやFirefoxやEdgeのブラウザ拡張である[Preact Devtools]との連携機能が含まれます。 + +``要素のネストが間違っている等の間違いを見つけると警告やエラーを出力します。 + +--- + +
    + +--- + +## インストール + +[Preact Devtools]はブラウザのウェブストアでインストールすることができます。 + +- [For Chrome](https://chrome.google.com/webstore/detail/preact-developer-tools/ilcajpmogmhpliinlbcdebhbcanbghmd) +- [For Firefox](https://addons.mozilla.org/en-US/firefox/addon/preact-devtools/) +- [For Edge](https://microsoftedge.microsoft.com/addons/detail/hdkhobcafnfejjieimdkmjaiihkjpmhk) + +インストールした後、`preact/debug`を`import`して拡張との接続を初期化する必要があります。 +この`import`はアプリケーション全体で**一番最初に**行われる必要があります。 + +> `preact-cli`は`preact/debug`を自動的に導入します。`preact-cli`を使っている場合、次のステップをスキップして大丈夫です。 + +アプリケーションのメインエントリーファイルに以下のように`preact/debug`を`import`します。 + +```jsx +// 最初に`import`する必要があります。 +import "preact/debug"; +import { render } from 'preact'; +import App from './components/App'; + +render(, document.getElementById('root')); +``` + +### Productionビルドからdevtoolsを削除する + +ほとんどのバンドラでは必ず使われない`if`文を見つけた場合、その分岐を削除します。 +これを利用してdevelopmentビルド時のみ`preact/debug`を含めることができます。そして、Productionビルド時には貴重なバイト数を節約することができます。 + +```jsx +// 最初に`import`する必要があります。 +if (process.env.NODE_ENV==='development') { + // `import`はトップレベルにのみ記述することができるため、ここではrequireを使います。 + require("preact/debug"); +} + +import { render } from 'preact'; +import App from './components/App'; + +render(, document.getElementById('root')); +``` + +ビルドツールで`NODE_ENV`変数が正しくセットされているか確認してください。 + +## デバッグ時の警告とエラー + +Preactが無効なコードを発見すると警告やエラーを表示することがあります。 +それらを修正してアプリケーションを完璧にしましょう。 + +### `undefined` parent passed to `render()`(`render()`に渡された親要素が`undefined`) + +これはコードがアプリケーションをDOMノードではなく何も存在しないところにレンダリングしようとしていることを意味します。 +両者の比較です。 + +```jsx +// Preactが受け取った物 +render(, undefined); + +// 期待しているもの +render(, actualDomNode); +``` + +このエラーが発生する主な理由は`render()`関数が実行される際にDOMが存在していないからです。 +存在することを確認して下さい。 + +### `undefined` component passed to `createElement()`(`createElement()`に`undefined`がコンポーネントとして渡された) + +Preactはコンポーネントの代わりに`undefined`を渡すとエラーをスローします。 +このエラーのよくある原因は`default export`と`named export`を取り違えていることです。 + +```jsx +// app.js +export default function App() { + return
    Hello World
    ; +} + +// index.js: because `app.js`は`named export`を行っていないので動作しません。 +import { App } from './app'; +render(, dom); +``` + +逆の場合も同じエラーがスローされます。 +それは`named export`と宣言して`default export`を使おうとする場合です。 +これを手早く確かめる方法は(エディタがまだそれを実行していない場合)`import`したものを単にログに出力することです。 + +```jsx +// app.js +export function App() { + return
    Hello World
    ; +} + +// index.js +import App from './app'; + +console.log(App); +// ログ: コンポーネントではなく { default: [Function] } が出力される +``` + +### Passed a JSX literal as JSX twice(渡されたJSXリテラルがJSXとして2度評価された) + +JSXリテラルもしくはコンポーネントをJSXに再度渡すことは無効です。それはエラーを引き起こします。 + +```jsx +const Foo =
    foo
    ; +// 無効: Fooは既にJSX要素です。 +render(, dom); +``` + +単に変数を直接渡すだけで修正することができます。 + +```jsx +const Foo =
    foo
    ; +render(Foo, dom); +``` + +### Improper nesting of table detected(テーブルの不適切なネストが見つかりました) + +HTMLにはテーブルの構造に対して非常に明確な決まりがあります。 +それから外れるとデバッグすることが非常に難しいレンダリングエラーが発生します。 +Preactはこれを見つけてエラーを出力します。 +テーブルの構造について詳しく知りたい場合は[MDNのドキュメント](https://developer.mozilla.org/en-US/docs/Learn/HTML/Tables/Basics)を読んでください。 + +### Invalid `ref`-property(無効な`ref`プロパティ) + +`ref`プロパティに不適切な値が含まれている場合、このエラーがスローされます。 +これには少し前に非推奨になった文字列ベースの`ref`プロパティも含まれます。 + +```jsx +// 有効 +
    {/* ... */)}} /> + +// 有効 +const ref = createRef(); +
    + +// 無効 +
    +``` + +### Invalid event handler(無効なイベントハンドラ) + +うっかり間違った値をイベントハンドラに渡すことがあるかもしれません。 +イベントハンドラに渡す値は常に`function`もしくは`null`(削除したい場合)でなければなりません。 +それ以外は無効です。 + +```jsx +// 有効 +
    console.log("click")} /> + +// 無効 +
    +``` + +### Hook can only be invoked from render methods(フックはrender()メソッドのみで実行することができる) + +このエラーはコンポーネントの外でフックを使用したときに発生します。 +フックは関数コンポーネントの内側でのみサポートされています。 + +```jsx +// 無効: コンポーネント内で使う必要があります。 +const [value, setValue] = useState(0); + +// 有効 +function Foo() { + const [value, setValue] = useState(0); + return ; +} +``` + +### Getting `vnode.[property]` is deprecated(`vnode.[property]`へのアクセスは非推奨です) + +Preact Xは内部の`vnode`のプロパティ名に互換性を破壊する変更を加えました。 + +| Preact 8.x | Preact 10.x | +| ------------------ | ---------------------- | +| `vnode.nodeName` | `vnode.type` | +| `vnode.attributes` | `vnode.props` | +| `vnode.children` | `vnode.props.children` | + +### Found children with the same key(子要素のkey属性が重複している) + +仮想DOMベースのライブラリは、子要素の移動を検知する必要があります。 +そのために、どの子要素がどれであるかを知るための情報が必要です。 +_これは動的に子要素を生成する場合にのみ必要です。_ + +```jsx +// 両方の子要素が同じ"A"keyを持っています。 +
    + {['A', 'A'].map(char =>

    {char}

    )} +
    +``` + +それを行う正しい方法はユニークなキーを付与することです。 +ほとんどの場合、反復処理の対象になるデータは何らかの形で`id`を持っているはずです。 + +```jsx +const persons = [ + { name: 'John', age: 22 }, + { name: 'Sarah', age: 24 } +]; + +// コンポーネントのrender部分 +
    + {persons.map(({ name, age }) => { + return

    {name}, Age: {age}

    ; + })} +
    +``` + +[Preact Devtools]: https://preactjs.github.io/preact-devtools/ diff --git a/content/ja/guide/v10/differences-to-react.md b/content/ja/guide/v10/differences-to-react.md new file mode 100755 index 000000000..24d21319c --- /dev/null +++ b/content/ja/guide/v10/differences-to-react.md @@ -0,0 +1,177 @@ +--- +name: Reactとの違い +permalink: '/guide/differences-to-react' +description: 'ReactとPreactの違いは何でしょう。このドキュメントはそれらを詳細に解説します。' +--- + +# Reactとの違い + +PreactはReactの再実装ではありません。両者には違いがあります。ほとんどの違いは些細な物か、[preact/compat]によって吸収されます。[preact/compat]はReactとの100%の互換性を目指している薄いレイヤーです。 + +PreactがReactの機能をすべて含まない理由は**小さい**、**集中した**状態を保ちたいからです。そうでないなら、単にReactプロジェクトを最適化する方が合理的です。Reactは既にとても複雑で素晴らしいアーキテクチャのコードベースで構成されています。 + +--- + +
    + +--- + +## 主な違い + +PreactとReactの主な違いはPreactには合成イベント(Synthetic Event)がないことです。 +Preactはイベント処理に内部でブラウザネイティブの`addEventListener`を使用しています。 +DOMイベントハンドラの完全なリストは[GlobalEventHandlers]を見てください。 + +ブラウザのイベントシステムは必要なすべての機能を満たしているので、Preactにとって合成イベントは意味がありません。 +合成イベントのようなカスタムイベントを完全に実装するとメンテナンスのオーバーヘッドが増加しAPIが複雑になってしまいます。 + +Reactの合成イベントとブラウザのネイティブイベントには以下のような違いがあります。 + +- ブラウザイベントは``コンポーネントをイベントバブリングで通過しません。 +- IE11で``要素の"x"クリアボタンは`input`イベントを発火しません。 +- (**`preact/compat`を使用していない場合は、**)``要素では`onChange`の代わりに`onInput`を使用してください。 + +その他の主な違いはDOMの仕様にもう少しだけ似せていることです。 +それの1つの例は`className`の代わりに`class`を使うことができることです。 + +## バージョンの互換性 + +preactと[preact/compat]の両方で、バーションの互換性はReactの現在と1つ前のメジャーリリースを比較します。 +新機能がReactチームによって発表された場合、[Projectの目的]にとって意味がある場合はPreactコアへの追加が検討されます。 +これはとても民主的なプロセスです。IssueやPull Requestでのオープンな議論や意思決定を通じて、Preactは継続的に進化しています。 + +> 従って、このウェブサイトとドキュメントのPreactとReactの互換性や比較はReact`16.x`と`15.x`を対象にしています。 + +## Preact固有の機能 + +Preactは(P)Reactコミュニティの活動から生まれたアイディアをベースに便利な機能を追加しています。 + +### `Component.render()`の引数 + +Preactでは、利便性のために、クラスコンポーネントの`this.props`と`this.state`を`render()`に引数として渡します。 +1つの`props`と1つの`state`を使用する以下のコンポーネントを見てください。 + +```jsx +// PreactとReactの両方で動作します。 +class Foo extends Component { + state = { age: 1 }; + + render() { + return
    Name: {this.props.name}, Age: {this.state.age}
    ; + } +} +``` + +Preactではこれを以下のように書くことができます。 + +```jsx +// Preactのみ動作します。 +class Foo extends Component { + state = { age: 1 }; + + render({ name }, { age }) { + return
    Name: {name}, Age: {age}
    ; + } +} +``` + +両方とも全く同じ物をレンダリングします。どちらのスタイルを選ぶかは単なる好みの問題です。 + +### そのままのHTML属性/プロパティ名 + +Preactは、すべての主要なブラウザでサポートされているDOMの仕様にReactより忠実です。 +Reactとの主な違いの1つは`className`属性の代わりに標準の`class`属性を使うことができることです。 + +```jsx +
    + +// 上記は下記と同じ +
    +``` + +両方ともサポートされていますが、ほとんどのPreact開発者は短く書くことができるので`class`を使うことを好みます。 + +### `onChange`の代わりに`onInput`を使う + +主に歴史的な事情によって、Reactの`onChange`イベントは、ブラウザによって提供されている`onInput`イベント(これは全てのブラウザで動作します)と同じ動作をします。 +一方で、Preactでは、`onChange`はユーザによって要素の値の変更が確定されたときに発生する[標準のDOMイベント](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event)です。 +フォームコントロールが変更された時に何かを行いたい場合、`onInput`イベントが適していることが多いです。 + +```jsx +// React + console.log(e.target.value)} /> + +// Preact + console.log(e.target.value)} /> +``` + +[preact/compat]では、Reactの挙動を再現するために、`onChange`が`onInput`と同じ動作になるよう内部で変換されます。 +これにより、Reactエコシステムとの最大限の互換性を確保しています。 + +### JSXコンストラクタ + +このアイディアは元は[hyperscript]と呼ばれていました。これはReactのエコシステムに限らず価値があります。 +だから、Preactは元のやり方を推奨しています。([詳しくは: why `h()`?](http://jasonformat.com/wtf-is-jsx)) +`h()`はトランスパイルされたコードを見ると`React.createElement`より少し読みやすいです。 + +```js +h( + 'a', + { href:'/' }, + h('span', null, 'Home') +); + +// vs +React.createElement( + 'a', + { href:'/' }, + React.createElement('span', null, 'Home') +); +``` + +ほとんどのPreactアプリケーションでは`h()`が使用されています。 +しかし、コアでは`h()`と`createElement()`の両方がサポートされています。 +どちらを使うかは重要ではありません。 + +### contextTypesは必要ありません + +Reactの古いコンテキストAPIではコンポーネントに`contextTypes`もしくは`childContextTypes`を実装する必要があります。 +Preactではこの制限はありません。すべてのコンポーネントは`getChildContext()`から生成されたすべての`context`の値を受け取ります。 + +## `preact`には無くて`preact/compat`にある機能 + +`preact/compat`はReactのコードをPreactに移行するための**互換**レイヤーです。 +既存のReactユーザはコードはそのままでバンドラの設定にいくつかのエイリアスをセットするだけで、とても手軽にPreactを試すことができます。 + +### Children API + +Reactの`Children`APIはコンポーネントの`children`を反復処理するためのAPIです。 +PreactではこのAPIは必要ありません。代わりにネイティブの配列のメソッドを使うことを推奨します。 + +```jsx +// React +function App(props) { + return
    {Children.count(props.children)}
    +} + +// Preact: 子コンポーネントを配列に変換します。配列の標準のプロパティを使います。 +function App(props) { + return
    {toChildArray(props.children).length}
    +} +``` + +### 固有のコンポーネントと関数 + +[preact/compat]は以下のような特殊な用途で使用することを目的としたコンポーネントや関数を提供しています。 + +- [PureComponent](/guide/v10/switching-to-preact#purecomponent): `props`もしくは`state`が変化した場合のみ更新されます。 +- [memo](/guide/v10/switching-to-preact#memo): `PureComponent`と用途が似ていますがこちらは比較のための関数を指定することができます。 +- [forwardRef](/guide/v10/switching-to-preact#forwardRef): 指定した子コンポーネントに`ref`をセットします。 +- [Portals](/guide/v10/switching-to-preact#portals): 指定した仮想DOMツリーを別のDOMコンテナにレンダリングします。 +- [Suspense](/guide/v10/switching-to-preact#suspense): **実験的機能** 仮想DOMツリーの準備ができていない間は代替の仮想DOMツリーのレンダリングすることを可能にします。 +- [lazy](/guide/v10/switching-to-preact#suspense): **実験的機能** 非同期のコードを遅延ロードします。そして、ロード完了を通知します。 + +[Projectの目的]: /about/project-goals +[hyperscript]: https://github.com/dominictarr/hyperscript +[preact/compat]: /guide/v10/switching-to-preact +[GlobalEventHandlers]: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers diff --git a/content/ja/guide/v10/external-dom-mutations.md b/content/ja/guide/v10/external-dom-mutations.md new file mode 100755 index 000000000..c7ffa99d2 --- /dev/null +++ b/content/ja/guide/v10/external-dom-mutations.md @@ -0,0 +1,90 @@ +--- +name: Preactのステート管理の範囲外のDOMとの連携 +permalink: '/guide/external-dom-mutations' +description: '直接DOMを操作するjQueryやその他のJavaScriptのスニペットとの連携' +--- + +# Preactのステート管理の範囲外のDOMとの連携 + +DOMを自由に操作したり、DOMにステートを保持したり、Preactコンポーネントとライブラリが生成したDOMを判別することができないサードパーティライブラリと連携する必要がある場合があります。そのような素晴らしいUIツールキットや再利用可能な部品が多く存在します。 + +このタイプのライブラリと連携するためには、サードパーティライブラリなどが行うDOMの変更を、Preactが上書きしてしまわないよう、仮想DOMのrendering/diffingアルゴリズムに教えてあげる必要があります + +--- + +
    + +--- + +## テクニック + +これはコンポーネントに`false`を返す`shouldComponentUpdate()`メソッドを定義するだけで簡単にできます。 + +```jsx +class Block extends Component { + shouldComponentUpdate() { + return false; + } +} +``` + +短く書くと以下のようになります。 + +```jsx +class Block extends Component { + shouldComponentUpdate = () => false; +} +``` + +このライフサイクルフックを追加して再レンダリングを抑止することで、コンポーネントが削除されるまでの間、そのDOMが更新されないようにすることができます。 +通常のコンポーネントと同様、ルートDOM要素は`this.base`で参照することができます。 +それは`render()`が返したルートJSX要素に対応するDOM要素です。 + +--- + +## 例 + +以下はコンポーネントの再レンダリングを"オフ"にする例です。 +この場合でも、`render()`は最初のDOM構造を生成するためにコンポーネントを生成し配置する過程で実行されることに注意してください。 + +```jsx +class Example extends Component { + shouldComponentUpdate() { + // 差分による再レンダリングをしません。 + return false; + } + + componentWillReceiveProps(nextProps) { + // 必要に応じてpropsが来たときの処理を書きます。 + } + + componentDidMount() { + // コンポーネントがDOMにマウントされました。自由にDOMを操作することができます。 + let thing = document.createElement('maybe-a-custom-element'); + this.base.appendChild(thing); + } + + componentWillUnmount() { + // コンポーネントがDOMから削除されます。DOMのクリーンアップ処理をここに書きます。 + } + + render() { + return
    ; + } +} +``` + + +## デモ + +[![デモ](https://i.gyazo.com/a63622edbeefb2e86d6c0d9c8d66e582.gif)](http://www.webpackbin.com/V1hyNQbpe) + +[**Webpackbinで動くデモを見る**](https://www.webpackbin.com/bins/-KflCmJ5bvKsRF8WDkzb) + + +## 実際の例 + +または、[preact-token-input](https://github.com/developit/preact-token-input/blob/master/src/index.js)で、このテクニックの使い方を確認してください。 +この例ではDOM内の足場としてコンポーネントを使用します。 +そして、コンポーネントの更新を無効にしてinput要素の処理を[tags-input](https://github.com/developit/tags-input)に引き継がせます。 +より複雑な例として[preact-richtextarea](https://github.com/developit/preact-richtextarea)があります。これは編集可能な`