中间件基本原理

    如果部件能够访问 DOM 信息,某些 web 应用程序需求就更容易实现。常见的例子有:

    • 响应式 UI 不与特定的设备类型绑定,而是根据可用的页面区域改变元素的大小。
    • 仅当某些元素在用户可视区域可见时,才延迟加载需要的数据——例如无限滚动列表。
    • 引导元素获取焦点,并在用户变更焦点后进行响应。

    但是,中间件并非必须与 DOM 绑定;这个概念还适合部件的渲染生命周期等更常用的情况。此类需求的常见示例如下:

    • 如果获取数据的开销大,则在渲染间缓存数据
    • 根据特定条件暂停和恢复部件的渲染;在所需信息不可用时,避免无用的渲染
    • 将函数部件标记为无效,以便 Dojo 可以重新渲染部件

    一个中间件组件一般公开的某些功能与部件渲染的 DOM 元素有关;大多是部件的根节点。中间件系统为部件在浏览器中的展示和交互提供了更高级的控制,并且允许部件以一致的方式使用几个新兴的 Web 标准。

    如果部件在其底层的 DOM 元素存在之前访问中间件的某些属性,则返回合理的默认值。还有一些中间件可以暂停部件的渲染,直到满足某些条件。使用这些中间件,部件能避免不必要的渲染,直到所需的信息可用为止,然后 Dojo 将在数据可用时获取中间件的正确属性值,自动重新渲染受影响的部件。

    中间件是使用 中的 create() 工厂方法定义的。这与创建函数部件的过程类似,但是中间件工厂返回的并不是 VDOM 节点,而是允许访问中间件功能集的 API。简单的中间件只需要一个函数调用来实现它们的需求,也可以直接返回一个函数,而不需要将中间件包装在一个对象中。

    中间件主要用在函数部件中,但也可以通过组合形成其他中间件,以实现更复杂的需求。这两种情况下,任何用到的中间件都会作为属性传给 create() 方法,然后通过部件或中间件工厂实现函数中的 middleware 参数使用这些中间件。

    例如,在部件中使用上面的 myMiddleware 中间件:

    src/widgets/MiddlewareConsumerWidget.tsx

    1. import { create, tsx } from '@dojo/framework/core/vdom';
    2. import myMiddleware from '../middleware/myMiddleware';
    3. export const MiddlewareConsumerWidget = render(({ middleware: { myMiddleware } }) => {
    4. return <div>{`Middleware value: ${myMiddleware.get()}`}</div>;
    5. });
    6. export default MiddlewareConsumerWidget;

    以下示例演示了用中间件组合出新的中间件,以实现更有用的需求:

    • 在本地缓存中取一个值
    • 如果缓存未命中,则从外部获取值
    • 在等待外部的值返回时,暂停使用该中间件的部件的进一步渲染
    • 一旦外部的值可以通过本地缓存访问,就恢复渲染并让使用的部件失效,以重新渲染这些部件

    由于中间件是通过 create() 工具函数定义的,因此为中间件指定属性接口的方式,与为函数部件指定属性接口的方式相同。主要的区别是中间件属性会被添加到所有消费者部件的属性接口中。这意味着属性值是在实例化部件时设置的,而不是在部件使用中间件时。在整个组合层次结构中,属性被看作是只读的,因此中间件不能修改属性值。

    下面是具有属性接口的中间件示例:

    src/middleware/middlewareWithProperties.tsx

    1. import { create } from '@dojo/framework/core/vdom';
    2. const factory = create().properties<{ conditional?: boolean }>();
    3. export const middlewareWithProperties = factory(({ properties }) => {
    4. return {
    5. return properties().conditional ? 'Conditional is true' : 'Conditional is false';
    6. }
    7. };
    8. });
    9. export default middlewareWithProperties;

    在部件中使用中间件及其属性:

    src/main.tsx

    1. import renderer, { tsx } from '@dojo/framework/core/vdom';
    2. import MiddlewarePropertiesWidget from './widgets/MiddlewarePropertiesWidget';