文档手册

Component Lifecycle

2024-07-18 14:28:53

Component Lifecycle

注意

本章以 RectJS/State and Lifecycle 文章为模型。它在概念上很接近,但使用不同的术语。

Data [Model] and Component Lifecycle

一般来说,Sciter's Reactor 是关于采用模型-视图-控制器成语的组件。

您有一些数据要呈现给用户。用户能够查看数据并对其进行操作。数据操作是一组代码函数和事件处理程序,它们作为一个组被命名为 Controller。

Component Class

让我们将滴答作响的时钟示例转换为可重用的时钟组件。

每个基于反应堆类的组件应具有 render() 以下方法:

class Clock extends Element {
render() {
return <div>
<h1>Hello, world!</h1>
<h2>It is {this.time.toLocaleTimeString()}.</h2>
</div>;
}
}

每次更新时都会调用该 render() 方法,但只要我们渲染 <Clock /> 到同一个 DOM 节点中,就会只使用 Clock 该类的单个实例。这使我们能够使用其他功能,例如本地状态和生命周期方法。

Adding Local Data Storage to a Class

按照惯例,组件的本地数据存储位于实例 this.data 的字段中:

class Clock extends Element 
{
// declaring local data storage with initial value
 time = new Date();

render() {
return <div>
<h1>Hello, world!</h1>
<h2>It is {this.time.toLocaleTimeString()} now.</h2>
</div>;
}
}

我们 render() 的方法现在呈现属性的内容 this

在当前版本中,类时钟仅呈现创建时确定的静态时间。让我们把它换做一个正在运行的时钟。

Adding Lifecycle Methods to a Class

每当 Clock 第一次渲染到 DOM 时,我们都想设置一个计时器——当创建真正的 DOM 元素时。在 ReactJS 中,这被称为“挂载”。当类的实例附加到 DOM 元素时,Sciter 运行时将调用 componentDidMount() 方法:

class Clock extends Element 
{
 time = new Date(); // setting initial state

componentDidMount() { // instance of the class is attached to real DOM
this.timer(1000, () => {
this.componentUpdate({ time:new Date() });
return true; // to keep the timer ticking
});
}

render() {
return <div>
<h1>Hello, world!</h1>
<h2>It is {this.time.toLocaleTimeString()} now.</h2>
</div>;
}
}

你在这里看到新的实体 - 启动计时器的 componentDidMount() 方法的实现。

定时器回调函数是奇迹发生的地方:

() => {
this.componentUpdate({ time:new Date() });
return true; // to keep the timer ticking
}

在每次计时器滴答时,它都会使用新数据调用内置 Element.prototype.componentUpdate(newdata) 方法。

Lifecycle methods of class components

开箱即用的 Sciter 支持以下生命周期方法:

  • constructor(props,kids) - 可选的 JavaScript 标准构造函数,在创建元素时由运行时调用一次。

  • this(props,kids) - 在以下两种情况下由运行时调用:

    换句话说: this(props,kids) 每次组件接收道具和/或孩子时都会调用方法。

    • 在初始构建时 - 在调用后 constructor() 和调用之前 render() 立即调用;

    • 在父组件渲染时 - 在之前 render() 调用;

  • componentDidMount() - 当元素附加到 DOM 树时由运行时调用 - 创建真正的 DOM 元素。

  • componentWillUnmount() - “destructor” 方法,当元素从 DOM 树中删除时调用。

  • componentUpdate(props) - 调用此方法以更新元素的状态。

  • render([props,kids]) - 必填项,每次需要[重新]渲染组件时都会调用此方法。它应返回有效的 JSX 文本定义元素的 DOM。

Updating component state

Sciter 中的内置类 Element 表示 DOM 元素。

在其他方法和属性中,该类提供了方法的 componentUpdate() 本机实现,该方法实现的逻辑接近于此:

class Element
{
componentUpdate(newdata = null) {
if(typeof newdata == "object")
Object.assign(this,newdata);
this.post(() => this.patch(this.render()));
}
}

如您所见,执行 componentUpdate(newdata) 以下操作:

  1. Object.assign(this,newdata); - 通过 newdata 对象的值更新此 DOM 对象的变量;

  2. { this.patch(this.render()); } - 定义本地更新方法

    • 调用 this.render() 方法生成虚拟 DOM 元素;

    • 调用本机 Element.patch(velement) 方法,使用 velement 定义来修补此现有 DOM 元素 render() ;

  3. this.post(updater) - 将更新调用计划到下一个事件处理周期。

延迟渲染逻辑可确保将多个 updater() 执行请求折叠为事件队列中的单个 updater() 调用请求。

Using Date Correctly

您应该了解三件事 componentUpdate(newdata)

Do Not Modify the Data Field Directly

例如,这不会重新渲染组件:

// WRONG!
this.comment = "Hello";

 请改用 componentUpdate()

// Correct
this.componentUpdate({comment: "Hello"});

唯一应该直接分配属性的地方是构造函数。

Data Updates are Merged

调用 componentUpdate(newdata) 时,您提供的对象的字段将合并到 DOM 元素的当前属性集中。

因此,您的代码可能会对数据的不同部分发出 componentUpdate() 请求,它们最终将在实际 DOM 元素和 render() 调用结果之间执行单个协调操作,因此:

clock.componentUpdate { time:new Date() };
...
clock.componentUpdate { greeting: "John" };

最终将进行单 clock.render() 次通话和屏幕更新。 提示

对上述内容发表评论。在 SciterJS 中,这:

obj.method { name:val };

是调用的缩写形式:

obj.method({ name:val });

这只是一种语法糖,让我们的开发人员的生活更轻松一些。