Component Lifecycle
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)
以下操作:
Object.assign(this,newdata);
- 通过 newdata 对象的值更新此 DOM 对象的变量;{ this.patch(this.render()); }
- 定义本地更新方法调用
this.render()
方法生成虚拟 DOM 元素;调用本机
Element.patch(velement)
方法,使用 velement 定义来修补此现有 DOM 元素render()
;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 });
这只是一种语法糖,让我们的开发人员的生活更轻松一些。