コンポーネント
コンポーネントはPreactの基本的な構成要素です。小さな構成要素から複雑なUIを簡単に構築するために不可欠です。また、レンダリングされた出力に状態を付加する役割も担っています。
Preactには2種類のコンポーネントがあり、このガイドで説明します。
関数コンポーネント
関数コンポーネントは、最初の引数として`props`を受け取るプレーンな関数です。JSXで動作させるには、関数名は**必ず**大文字で始める必要があります。
function MyComponent(props) {
return <div>My name is {props.name}.</div>;
}
// Usage
const App = <MyComponent name="John Doe" />;
// Renders: <div>My name is John Doe.</div>
render(App, document.body);
REPLで実行以前のバージョンでは`「Stateless Components」`として知られていました。これはフックアドオンではもはや当てはまりません。
クラスコンポーネント
クラスコンポーネントは、状態とライフサイクルメソッドを持つことができます。後者は、コンポーネントがDOMにアタッチされたり、破棄されたりする際に呼び出される特殊なメソッドです。
ここでは、現在時刻を表示する`<Clock>`というシンプルなクラスコンポーネントがあります。
class Clock extends Component {
constructor() {
super();
this.state = { time: Date.now() };
}
// Lifecycle: Called whenever our component is created
componentDidMount() {
// update time every second
this.timer = setInterval(() => {
this.setState({ time: Date.now() });
}, 1000);
}
// Lifecycle: Called just before our component will be destroyed
componentWillUnmount() {
// stop when not renderable
clearInterval(this.timer);
}
render() {
let time = new Date(this.state.time).toLocaleTimeString();
return <span>{time}</span>;
}
}
REPLで実行ライフサイクルメソッド
時計の時刻を毎秒更新するには、`<Clock>`がDOMにマウントされた時点を知る必要があります。 *HTML5カスタムエレメントを使用したことがある場合、これは`attachedCallback`と`detachedCallback`ライフサイクルメソッドに似ています。* Preactは、コンポーネントに対して定義されている場合、以下のライフサイクルメソッドを呼び出します。
ライフサイクルメソッド | 呼び出されるタイミング |
---|---|
componentWillMount() | (非推奨) コンポーネントがDOMにマウントされる前 |
componentDidMount() | コンポーネントがDOMにマウントされた後 |
componentWillUnmount() | DOMから削除される前 |
componentWillReceiveProps(nextProps, nextContext) | 新しいpropsが受け入れられる前 *(非推奨)* |
getDerivedStateFromProps(nextProps, prevState) | `shouldComponentUpdate` の直前。状態を更新するオブジェクトを返すか、更新をスキップするには `null` を返します。注意して使用してください。 |
shouldComponentUpdate(nextProps, nextState, nextContext) | `render()` の前。レンダリングをスキップするには `false` を返します。 |
componentWillUpdate(nextProps, nextState, nextContext) | `render()` の前 *(非推奨)* |
getSnapshotBeforeUpdate(prevProps, prevState) | `render()` の直前に呼び出されます。戻り値は `componentDidUpdate` に渡されます。 |
componentDidUpdate(prevProps, prevState, snapshot) | `render()` の後 |
それらが互いにどのように関連しているかの視覚的な概要を次に示します(元々はDan Abramovによるツイートに投稿されました)
エラーバウンダリ
エラーバウンダリは、`componentDidCatch()`または静的メソッド`getDerivedStateFromError()`(またはその両方)を実装するコンポーネントです。これらは、レンダリング中に発生するエラーをキャッチできる特別なメソッドであり、通常はより良いエラーメッセージやその他のフォールバックコンテンツを提供し、ログ記録のために情報を保存するために使用されます。エラーバウンダリはすべてのエラーをキャッチできず、イベントハンドラまたは非同期コード(`fetch()`呼び出しなど)でスローされたエラーは別途処理する必要があることに注意することが重要です。
エラーがキャッチされると、これらのメソッドを使用してエラーに対応し、適切なエラーメッセージやその他のフォールバックコンテンツを表示できます。
class ErrorBoundary extends Component {
constructor() {
super();
this.state = { errored: false };
}
static getDerivedStateFromError(error) {
return { errored: true };
}
componentDidCatch(error, errorInfo) {
errorReportingService(error, errorInfo);
}
render(props, state) {
if (state.errored) {
return <p>Something went badly wrong</p>;
}
return props.children;
}
}
REPLで実行フラグメント
Fragment
を使用すると、一度に複数の要素を返すことができます。これらは、JSXの制限(すべての「ブロック」には単一のルート要素が必要です)を解決します。リスト、テーブル、またはCSSフレックスボックスと組み合わせて使用されることが多く、そうでなければ中間要素がスタイルに影響を与えます。
import { Fragment, render } from 'preact';
function TodoItems() {
return (
<Fragment>
<li>A</li>
<li>B</li>
<li>C</li>
</Fragment>
)
}
const App = (
<ul>
<TodoItems />
<li>D</li>
</ul>
);
render(App, container);
// Renders:
// <ul>
// <li>A</li>
// <li>B</li>
// <li>C</li>
// <li>D</li>
// </ul>
REPLで実行ほとんどの最新のトランスパイラでは、Fragment
のより短い構文を使用できます。短い方がはるかに一般的であり、通常は目にするものです。
// This:
const Foo = <Fragment>foo</Fragment>;
// ...is the same as this:
const Bar = <>foo</>;
コンポーネントから配列を返すこともできます。
function Columns() {
return [
<td>Hello</td>,
<td>World</td>
];
}
ループ内で作成する場合は、Fragment
にキーを追加することを忘れないでください。
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
// Without a key, Preact has to guess which elements have
// changed when re-rendering.
<Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment>
))}
</dl>
);
}