dojo dragon main logo

资源中间件

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 函数的结果应在使用 getOrReadisLoadingisFailedfind API 时使用。使用 options 而不是构造一个新的 ResourceOptions 对象非常重要,以确保资源在选项更改时正确失效。

const options = createOptions('id');

生成的 options 变量是一个函数,可用于设置和获取实例选项数据。

interface ResourceOptions<S> {
	page: number | number[];
	query: ResourceQuery<S>;
	size: number;
}

getOrRead()

getOrRead 函数接受一个 templateResourceOptions 以及模板所需的任何 initOptionsgetOrRead 返回一个数据数组,用于传递的 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 对象可以传递以指定对数据属性的过滤器。如果 transformtemplate 一起传递,则此 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 函数接受 templateResourceFindOptions 以及模板所需的 initOptionsfind 返回 ResourceFindResultundefined,具体取决于是否可以找到该项目。ResourceFindResult 包含标识的项目、资源数据集的索引、项目所属的页面(基于 ResourceFindOptionsoptions 属性中设置的页面大小)以及该页面上项目的索引。如果 find 结果尚未为 resource 存储所知,并且请求是异步的,则 find 调用将返回 undefined,并在查找结果可用时使小部件失效。

ResourceFindOptions 需要一个起始索引 startResourceOptions options、搜索类型 typecontains 是默认的查找类型)以及查找操作的查询对象。

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 函数接受一个 templateResourceOptionsResourceFindOptions 对象,以及模板所需的 initOptionsisLoading 返回一个 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 函数接受一个 templateResourceOptionsResourceFindOptions 对象以及模板所需的 initOptionsisFailed 返回一个 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>;
});