dojo dragon main logo

资源概念

Dojo 资源旨在为 Dojo 应用程序中处理数据提供一种一致且连贯的机制。Dojo 资源有两个核心概念。

  • 资源模板
  • 资源中间件

模板

资源模板是资源用来处理资源数据的描述。资源模板足够灵活,可以将资源连接到多个不同的提供者,例如 RESTful API 或客户端数据。

模板应该是无状态的,这样就可以通过使用资源选项来确定所需的数据,以及使用资源控件来与资源存储交互(例如将数据放入存储)的方式在整个应用程序中重复使用模板。

模板是使用 @dojo/framework/core/middleware/resources 模块中的 createResourceTemplate 工厂创建的。资源模板的 API 是灵活的,可以在创建模板时定义,但是默认情况下,API 需要一个名为 read 的函数,该函数用于接收请求并使用模板 controls 存储资源数据。

userResourceTemplate.ts

import { createResourceTemplate } from '@dojo/framework/core/middleware/resources';

interface User {
	firsName: string;
	lastName: string;
	username: string;
	email: string;
}

// The type for the data is passed to the `createResourceTemplate` factory
export default createResourceTemplate<User>({
	idKey: 'email', // This indicates that email is the unique key of the resource
	read: (request, controls) => {
		// use the `request` to "fetch" the data from the data-source
		// and use the controls to set the data in the resource
	}
});

资源控件被注入到所有数据模板函数中,以支持与后备资源存储交互。控件包含一个 put 函数,用于根据请求设置资源中的数据。

中间件

resource 中间件是与资源模板和“资源感知”小部件交互所需的接口。中间件公开了一个 API,可用于以一致且可预测的方式在小部件中使用模板。

MyResourceAwareWidget.tsx

import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';

import FancyLoadingIndicator from './FancyLoadingIndicator';

// The resource item interface
interface ResourceItem {
	label: string;
}

// create the resource middleware passing the type of the resource required
// passing the generic type means that the `resource` property will
// be exposed on the widget's property interface
const resource = createResourceMiddleware<ResourceItem>();

// pass the created middleware to the `create` function
const factory = create({ resource });

export default factory(function MyResourceAwareWidget({ id, properties, middleware: { resource } }) {
	// get the `template` and `options` from the widgets properties the options are optional so need to be defaulted using the
	// createOptions function from `resource`
	const {
		resource: { template, options = resource.createOptions((curr, next) => ({ ...curr, ...next })) }
	} = properties();

	// de-structure the required resource APIs, these can also be accessed
	// directly from `resource`
	const {
		get,
		template: { read }
	} = resource.template(template);

	// Call `get` with the `read` API to request the data based on the `options`
	// passing the `meta: true` option to get meta information including the loading
	// state.
	const {
		data,
		meta: { status }
	} = get(options({ page: 1, size: 20 }), { read, meta: true });
	// Check if the resource is current loading
	if (status === 'reading') {
		// if the resource is loading return a fancy loading indicator
		return <FancyLoadingIndicator />;
	}
	// If the items have been loaded return them in a list
	return <div>{items.map(({ item }) => <li>{item.label}</li>)}</div>;
});