资源概念
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>;
});