教程
本指南将逐步构建一个简单的“滴答时钟”组件。如果您不熟悉虚拟 DOM,请尝试完整的 Preact 教程。
:information_desk_person: 本指南假设您已完成入门文档并已成功设置工具。如果没有,请从Vite开始。
Hello World
开箱即用,您将在任何 Preact 代码库中始终看到的两个函数是h()
和render()
。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
渲染文本是一个开始,但我们希望让我们的应用程序更具交互性。我们希望在数据更改时对其进行更新。:star2
我们的最终目标是创建一个应用程序,用户可以在其中输入姓名并在提交表单时显示姓名。为此,我们需要一个可以存储我们提交内容的地方。这就是组件发挥作用的地方。
因此,让我们将我们现有的应用程序变成组件
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, [userinput]!"
,因此我们需要一种方法来了解当前输入值。
我们将其存储在我们的组件的一个名为 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
事件添加一个处理程序。不同之处在于它写入我们 state
的另一个名为 name
的属性。然后,我们交换标题并在那里插入我们的 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 中运行我们又做到了!现在我们有了 一个滴答作响的时钟!