チュートリアル
このガイドでは、シンプルな「カウントダウンタイマー」コンポーネントの作成手順を説明します。バーチャルDOMを初めて使用する場合は、Preactの完全なチュートリアルをご覧ください。
ℹ️ このガイドでは、はじめにドキュメントを完了し、ツールを正常に設定済みであることを前提としています。そうでない場合は、Viteから始めましょう。
Hello World
Preactコードベースでは、常に`h()`と`render()`という2つの関数を見かけます。`h()`関数は、JSXをPreactが理解できる構造に変換するために使用されます。ただし、JSXを使用せずに直接使用することもできます。
// With JSX
const App = <h1>Hello World!</h1>;
// ...the same without JSX
const App = h('h1', null, 'Hello World');
これだけでは何も起こりません。Hello WorldアプリをDOMに挿入する必要があります。そのためには、`render()`関数を使用します。
import { render } from 'preact';
const App = <h1>Hello World!</h1>;
// Inject our app into the DOM
render(App, document.getElementById('app'));
REPLで実行おめでとうございます!最初のPreactアプリを作成しました!
インタラクティブなHello World
テキストのレンダリングは最初のステップですが、アプリをもう少しインタラクティブにしたいです。データの変更時に更新できるようにしたいです。🌟
最終的な目標は、ユーザーが名前を入力して、フォームを送信すると名前が表示されるアプリを作成することです。そのためには、送信した内容を保存できる何かが必要です。ここでコンポーネントが役立ちます。
それでは、既存のAppをコンポーネントに変換しましょう。
import { h, render, Component } from 'preact';
class App extends Component {
render() {
return <h1>Hello, world!</h1>;
}
}
render(<App />, document.getElementById("app"));
REPLで実行先頭に新しい`Component`インポートが追加され、`App`がクラスに変換されていることに気付くでしょう。これだけでは役に立ちませんが、次にやるべきことの準備段階です。さらに面白くするために、テキスト入力と送信ボタン付きのフォームを追加します。
import { h, render, Component } from 'preact';
class App extends Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<form>
<input type="text" />
<button type="submit">Update</button>
</form>
</div>
);
}
}
render(<App />, document.getElementById("app"));
REPLで実行さあ、本格的になってきました!実際のアプリらしくなってきました!しかし、まだインタラクティブにする必要があります。「Hello world!」を「Hello, [ユーザー入力]! 」に変更したいので、現在の入力値を知る方法が必要です。
コンポーネントの`state`と呼ばれる特別なプロパティに保存します。これは特別なプロパティで、`setState`メソッドを介して更新されると、Preactは状態を更新するだけでなく、このコンポーネントのレンダリング要求もスケジュールします。要求が処理されると、コンポーネントは更新された状態を使用して再レンダリングされます。
最後に、`value`を設定し、`input`イベントにイベントハンドラをアタッチして、新しい状態を入力にアタッチする必要があります。
import { h, render, Component } from 'preact';
class App extends Component {
// Initialise our state. For now we only store the input value
state = { value: '' }
onInput = ev => {
// This will schedule a state update. Once updated the component
// will automatically re-render itself.
this.setState({ value: ev.currentTarget.value });
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<form>
<input type="text" value={this.state.value} onInput={this.onInput} />
<button type="submit">Update</button>
</form>
</div>
);
}
}
render(<App />, document.getElementById("app"));
REPLで実行現時点では、ユーザー視点ではアプリはそれほど変わっていませんが、次のステップですべてをまとめます。
入力と同様に、`<form>`の`submit`イベントにハンドラを追加します。違いは、`name`と呼ばれる`state`の別のプロパティに書き込むことです。そして、見出しを入れ替え、そこに`state.name`の値を挿入します。
import { h, render, Component } from 'preact';
class App extends Component {
// Add `name` to the initial state
state = { value: '', name: 'world' }
onInput = ev => {
this.setState({ value: ev.currentTarget.value });
}
// Add a submit handler that updates the `name` with the latest input value
onSubmit = ev => {
// Prevent default browser behavior (aka don't submit the form here)
ev.preventDefault();
this.setState({ name: this.state.value });
}
render() {
return (
<div>
<h1>Hello, {this.state.name}!</h1>
<form onSubmit={this.onSubmit}>
<input type="text" value={this.state.value} onInput={this.onInput} />
<button type="submit">Update</button>
</form>
</div>
);
}
}
render(<App />, document.getElementById("app"));
REPLで実行できました!これで、カスタム名を入力して「更新」をクリックすると、新しい名前がヘッダーに表示されます。
クロックコンポーネント
最初のコンポーネントを作成したので、もう少し練習しましょう。今度は時計を作成します。
import { h, render, Component } from 'preact';
class Clock extends Component {
render() {
let time = new Date().toLocaleTimeString();
return <span>{time}</span>;
}
}
render(<Clock />, document.getElementById("app"));
REPLで実行簡単ですね!問題は、時間が変わらないことです。時計コンポーネントをレンダリングした時点の時刻で固定されています。
そこで、コンポーネントがDOMに追加されたら1秒タイマーが開始し、削除されたら停止するようにします。`componentDidMount`でタイマーを作成し、その参照を保存し、`componentWillUnmount`でタイマーを停止します。タイマーが刻むごとに、新しい時間値でコンポーネントの`state`オブジェクトを更新します。これにより、コンポーネントが自動的に再レンダリングされます。
import { h, render, Component } from 'preact';
class Clock extends Component {
state = { time: Date.now() };
// Called whenever our component is created
componentDidMount() {
// update time every second
this.timer = setInterval(() => {
this.setState({ time: Date.now() });
}, 1000);
}
// 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>;
}
}
render(<Clock />, document.getElementById("app"));
REPLで実行またできました!これで、動く時計ができました!