资源中间件
resource
中间件是使用资源模板和访问资源所必需的。中间件可以选择性地根据是否将接口传递给 createResourceMiddleware
工厂来自动装饰小部件所需的 resource
属性。resource
属性由小部件用于与传递的任何资源进行交互。传递给小部件的 resource
中间件是一个工厂,它返回用于处理资源的完整 API。最简单的场景是使用 resource
中间件来返回请求页面的数据。这是使用 getOrRead
API 完成的,该 API 需要模板和资源选项:getOrRead(template, options())
。getOrRead
函数被设计为响应式的,因此如果数据不可立即获取 - 例如,资源是异步的,并且尚未为提供的选项读取 - 它将为请求的每个页面返回 undefined
,允许小部件处理“加载”数据场景。
resource
属性包含 template
和一组可选的 options
,它们用于与 template
的资源存储进行交互。由于 options
可以是未定义的,因此需要使用 createOptions
API 创建的选项对其进行默认设置。createOptions
函数接受一个标识符,用于在渲染之间跟踪选项。此 id
通常可以使用注入到小部件中的小部件的 id
以及属性、子级和中间件。
MyResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
interface ResourceData {
value: string;
label: string;
}
const resource = createResourceMiddleware<ResourceData>();
const factory = create({ resource });
export default factory(function MyDataAwareWidget({ id, properties, resource }) {
const { getOrRead, createOptions } = resource;
const {
resource: { template, options = createOptions(id) }
};
const [items] = getOrRead(template, options());
if (!items) {
return <div>Loading...</div>;
}
return <ul>{items.map((item) => <li>{item.label}</li>)}</ul>;
});
resource
中间件 API
createOptions()
createOptions
创建一个新的选项实例,可用于 resource
API。需要一个 id
来在渲染之间标识选项的实例。createOptions
函数的结果应在使用 getOrRead
、isLoading
、isFailed
和 find
API 时使用。使用 options
而不是构造一个新的 ResourceOptions
对象非常重要,以确保资源在选项更改时正确失效。
const options = createOptions('id');
生成的 options
变量是一个函数,可用于设置和获取实例选项数据。
interface ResourceOptions<S> {
page: number | number[];
query: ResourceQuery<S>;
size: number;
}
getOrRead()
getOrRead
函数接受一个 template
、ResourceOptions
以及模板所需的任何 initOptions
。getOrRead
返回一个数据数组,用于传递的 ResourceOptions
中请求的每个页面。如果数据尚不可用,它将使用传递的模板执行 read
。一旦数据已设置在资源中,小部件将以响应方式失效。
MyResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
const resource = createResourceMiddleware<{ value: string }>();
const factory = create({ resource });
export default factory(function MyDataAwareWidget({ id, properties, middleware: { resource } }) {
const { getOrRead, createOptions } = resource;
const {
resource: { template, options = createOptions(id) }
} = properties();
const [pageTenItems] = getOrRead(options({ page: 10, size: 30 }));
if (!pageTenItems) {
return <div>Loading...</div>;
}
return <ul>{pageTenItems.map((item) => <li>{item.label}</li>)}</ul>;
});
query
对象可以传递以指定对数据属性的过滤器。如果 transform
与 template
一起传递,则此 query
对象将在传递给资源模板的 read
函数时映射回原始资源的键。
MyResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
const resource = createResourceMiddleware<{ value: string }>();
const factory = create({ resource });
export default factory(function MyDataAwareWidget({ id, properties, middleware: { resource } }) {
const { getOrRead, createOptions } = resource;
const {
resource: { template, options = createOptions(id) }
} = properties();
const [pageTenItems] = getOrRead(template, options({ page: 10, size: 30, query: { value: 'query-value' } }));
if (!pageTenItems) {
return <div>Loading...</div>;
}
return <ul>{pageTenItems.map((item) => <li>{item.label}</li>)}</ul>;
});
可以在 options
中传递多个页面。请求的每个页面都将在结果数组中返回。当请求多个页面时,检查第一个数组值以确定 getOrRead
调用是否可以完成是不安全的,因为它的 API 将返回任何可用的页面并对其余页面进行请求。要检查请求的状态,可以将选项传递到 isLoading
API 中。页面按它们在 options
中指定的顺序返回。如果需要,在页面数组完全加载后,可能需要对其使用 .flat()
,以将单个页面结果合并到单个列表中。
MyResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
const resource = createResourceMiddleware<{ value: string }>();
const factory = create({ resource });
export default factory(function MyDataAwareWidget({ id, properties, middleware: { resource } }) {
const { getOrRead, createOptions } = resource;
const {
resource: { template, options = createOptions(id) }
} = properties();
// [pageOne, pageTwo, pageThree, pageFour]
const items = getOrRead(options({ page: [1, 2, 3, 4], size: 30 }));
if (!isLoading(options())) {
return <div>Loading...</div>;
}
return <ul>{items.flat().map((item) => <li>{item.label}</li>)}</ul>;
});
meta()
meta
API 返回资源的当前元信息,包括当前选项本身。MetaResponse
还包含注册的资源 total
,可用于确定条件逻辑,例如虚拟渲染。
meta(template, options, request): MetaResponse;
meta(template, options, initOptions, request): MetaResponse;
MyResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
const resource = createResourceMiddleware<{ value: string }>();
const factory = create({ resource });
export default factory(function MyDataAwareWidget({ id, properties, middleware: { resource } }) {
const { meta, createOptions } = resource;
const {
resource: { template, options = createOptions(id) }
} = properties();
// get the meta info for the current options
const metaInfo = meta(template, options());
if (metaInfo && metaInfo.total > 0) {
// do something if there is a known total
}
});
默认情况下,调用 meta 不会启动请求。如果没有元信息 - 例如,getOrRead
尚未被调用 - 它永远不会填充它们并且不会在没有单独调用 getOrRead
的情况下失效。可以将一个额外的参数 request
作为 true
传递,以便在没有现有元信息的情况下对传递的选项进行请求。
MyResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
const resource = createResourceMiddleware<{ value: string }>();
const factory = create({ resource });
export default factory(function MyDataAwareWidget({ id, properties, middleware: { resource } }) {
const { meta, createOptions } = resource;
const {
resource: { template, options = createOptions(id) }
} = properties();
// get the meta info for the current options and make a `getOrRead`
// request if there is no existing meta information. Once the request
// is completed the widget will re-render with the meta information
const metaInfo = meta(template, options(), true);
if (metaInfo && metaInfo.total > 0) {
// do something if there is a known total
}
});
find()
find
函数接受 template
、ResourceFindOptions
以及模板所需的 initOptions
。find
返回 ResourceFindResult
或 undefined
,具体取决于是否可以找到该项目。ResourceFindResult
包含标识的项目、资源数据集的索引、项目所属的页面(基于 ResourceFindOptions
中 options
属性中设置的页面大小)以及该页面上项目的索引。如果 find
结果尚未为 resource
存储所知,并且请求是异步的,则 find
调用将返回 undefined
,并在查找结果可用时使小部件失效。
ResourceFindOptions
需要一个起始索引 start
、ResourceOptions
options
、搜索类型 type
(contains
是默认的查找类型)以及查找操作的查询对象。
interface ResourceFindOptions {
options: ResourceOptions;
start: number;
type: 'exact' | 'contains' | 'start';
query: ResourceQuery;
}
MyResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
const resource = createResourceMiddleware<{ value: string }>();
const factory = create({ resource });
export default factory(function MyDataAwareWidget({ id, properties, middleware: { resource } }) {
const { find, createOptions } = resource;
const {
resource: { template, options = createOptions(id) }
} = properties();
const item = find(template, { options: options(), start: 0, type: 'contains', query: { value: 'find query' } });
if (item) {
return <div>{/* do something with the item */}</div>;
}
return <div>Loading</div>;
});
isLoading()
isLoading
函数接受一个 template
、ResourceOptions
或 ResourceFindOptions
对象,以及模板所需的 initOptions
。isLoading
返回一个 boolean
值,以指示是否正在进行对传递的选项的读取。
MyResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
const resource = createResourceMiddleware<{ value: string }>();
const factory = create({ resource });
export default factory(function MyDataAwareWidget({ id, properties, middleware: { resource } }) {
const { getOrRead, isLoading, createOptions } = resource;
const {
resource: { template, options = createOptions(id) }
} = properties();
const [items] = getOrRead(template, options({ page: 1, size: 30 }));
if (!isLoading(template, options())) {
return <div>Loading...</div>;
}
return <ul>{items().map((item) => <li>{item.label}</li>)}</ul>;
});
isFailed()
isFailed
函数接受一个 template
、ResourceOptions
或 ResourceFindOptions
对象以及模板所需的 initOptions
。isFailed
返回一个 boolean
值,以指示是否正在进行对传递的选项的读取。
MyResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
const resource = createResourceMiddleware<{ value: string }>();
const factory = create({ resource });
export default factory(function MyDataAwareWidget({ id, properties, middleware: { resource } }) {
const { getOrRead, isLoading, createOptions } = resource;
const {
resource: { template, options = createOptions(id) }
} = properties();
const [items] = getOrRead(template, options({ page: 1, size: 30 }));
if (!isFailed(template, options())) {
return <div>Failed...!</div>;
}
return <ul>{items().map((item) => <li>{item.label}</li>)}</ul>;
});