Dojo 资源
Dojo 资源旨在提供一致的模式,使小部件“资源感知”。资源可以配置为与任何类型的数据源一起使用。资源本质上是一个 Dojo 管理的数据存储,具有内置的缓存、分页、过滤和自定义 API。结合 resource
中间件,资源允许小部件一致地、与源无关地访问数据,而无需小部件了解获取实现或原始数据格式。
功能 | 描述 |
---|---|
支持任何类型的数据源 | 资源可以使用预加载数据或来自外部源的数据作为后端。 |
单个数据源 | 资源允许为给定模板创建一个单个数据源,该数据源可以使用数据中间件在多个小部件之间共享。 |
支持异步和同步数据读取 | 资源模板可以以任何方式读取数据 - 一旦数据可用,资源中间件就会对任何受影响的小部件进行响应式失效。 |
数据转换 | 允许指定小部件所需的数据格式,并透明地将源数据转换为小部件消费的预期输出格式 |
一致的资源选项 | 资源选项对象被传递给旨在读取数据的 API。 |
可共享的资源选项 | 资源选项可以通过资源中间件在小部件之间共享,允许多个小部件对资源更改(如页面更改)做出反应 |
基本用法
为了使用 Dojo 资源,小部件需要使用 resource
中间件,该中间件使用 @dojo/framework/middleware/resources
中的 createResourceMiddleware
工厂创建。有两种类型的“资源感知”小部件:在属性 API 上公开 resource
的小部件和小部件需要在内部使用资源。相同的工厂用于创建这两种类型的中间件,但主要区别在于,对于需要通过属性传递资源的小部件,在创建时需要资源类型。
interface ResourceData {
id: string;
name: string;
}
// Add `resource` to the widgets API
const resource = createResourceMiddleware<ResourceData>();
// For using resources internally only, no property is added to the
// widget property API
const resource = createResourceMiddleware();
使用 resource
中间件可以让你在小部件中使用资源模板。资源模板使用 @dojo/framework/middleware/resources
中的 createResourceTemplate
工厂创建。如果未将自定义模板传递给 createResourceTemplate
工厂,则将使用默认资源模板。
要创建一个默认模板,需要一个泛型来定义资源数据的类型和资源数据的 idKey
,这意味着资源将视为数据的唯一 ID 的属性。
interface ResourceData {
id: string;
name: string;
}
const template = createResourceTemplate<ResourceData>('id');
默认模板需要使用 id
初始化以标识资源实例和资源的数据数组,这可以在使用已加载的数据集时使用。需要初始化的模板需要被调用以创建可用于资源的“已加盖印章”模板。
template({ id: 'id', data: [{ id: '1', name: 'First' }] });
对于基本用法场景,传递模板不需要在小部件内部导入和使用 resource
中间件。如果资源数据接口和小部件所需的数据接口匹配,并且不需要自定义选项,则可以将模板直接传递给 resource
属性。如果需要默认模板,则不需要模板,因为 Dojo 资源将自动使用传递给资源的对象中的 id
、data
和 idKey
创建默认模板。
App.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceTemplate } from '@dojo/framework/core/middleware/resources';
import ResourceAwareWidget from './ResourceAwareWidget';
interface ResourceData {
id: string;
name: string;
}
const myTemplate = createResourceTemplate<{ id: string }>();
const factory = create();
const App = factory(function App({ id }) {
return (
<div>
<ResourceAwareWidget resource={template({ id, data })} />
<ResourceAwareWidget resource={{ id, data, idKey: 'id' }} />
</div>
});
自定义模板的数据源
Dojo 资源可以配置为用户定义的数据源,例如 RESTful API。这可以通过使用 createResourceTemplate
工厂创建具有 read
API 自定义实现的资源模板来完成。read
函数接收包含详细信息的请求,包括偏移量、页面大小和一组控件,其中包括用于“设置”读取响应的 put
。
userResourceTemplate.tsx
import { createResourceTemplate } from '@dojo/framework/core/middleware/resources';
interface RemoteResourceData {
id: string;
name: string;
}
export default createResourceTemplate<RemoteResourceData>({
idKey: 'id',
read: async (request: ResourceReadRequest, controls: ResourceControls) => {
// The template is injected with read request, offset, size and query
const { offset, size } = request;
// The request details are used to determine the data to fetch
const response = await fetch(`https://my.user.endpount.com?offset=${offset}&size=${size}`);
const data = await response.json();
// The template needs to set the response using the resource controls put function
// along with the original request
controls.put({ data: data.data, total: data.total }, request);
}
});
在小部件中访问数据
“资源感知”小部件需要使用 resource
中间件,该中间件提供了一个 API 来使用资源模板。resource
中间件需要使用 @dojo/framework/core/middleware/resources
中的 createResourceMiddleware
工厂创建,并传递一个接口,该接口定义了小部件的预期 resource
数据结构。
在小部件中访问数据是使用 get
函数从返回值中执行的,方法是将模板传递给 resource.template
工厂。get
函数需要标准选项 offset
、size
和 query
。Dojo 资源提供了一种标准机制 createOptions
(来自资源中间件),用于创建和管理选项,包括确保在“共享”选项更新时使小部件失效。createOptions
工厂接受一个函数,该函数在选项更新时被调用,允许选项的所有者控制更改,并将当前选项和下一个选项传递给 setter。
const { createOptions } = resource;
// by default, the setter will normally need to merge the next
// options over the current options
const options = createOptions((curr, next) => {
return { ...curr, ...next };
});
// however if certain queries are always required for the resource
// such as an "id' that can be always set
const options = createOptions((curr, next) => {
return { ...curr, ...next, query: { ...next.query, id: 'my-id' } };
});
默认情况下,get
函数不会尝试从模板读取,只会尝试使用现有数据来满足请求。为了确保 Dojo 资源在无法满足请求时尝试读取数据,需要将“read”函数传递给 get
函数。
const {
createOptions,
get,
template: { read }
} = resource.template(myTemplate);
const options = createOptions((curr, next) => ({ ...curr, ...next }));
const data = get(options(), { read });
如果资源模板上的 read
函数是异步的,则在获取数据时结果可能是 undefined
,并且当数据可用时,小部件将重新渲染。
ResourceAwareWidget.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
interface ResourceData {
value: string;
}
const resource = createResourceMiddleware<ResourceData>('value');
const factory = create({ resource });
export const DataAwareWidget = factory(function DataAwareWidget({ id, properties, middleware: { resource } }) {
const {
resource: { template, options = resource.createOptions(id) }
} = properties();
const {
get,
template: { read }
} = resource.template(template);
const items = get(options(), { read });
if (items) {
return <ul>{items.map((item) => <li>{item.value}</li>)}</ul>;
}
return <div>Loading...</div>;
});