integrate todolist with api

This commit is contained in:
Bowen Tan 2021-09-08 14:21:16 +08:00
parent 7b6555dc59
commit a5b22a8ac1
2 changed files with 132 additions and 119 deletions

View File

@ -9,31 +9,34 @@
<div id="root"></div>
<script type="module">
import renderApp from '../../src/main.tsx';
const listdata = [
const refresh = [
{
id: 1,
name: '马云',
email: 'jack.ma@deck.com',
componentId: 'nameInput',
method: {
name: 'setInputValue',
parameters: {
value: ``,
},
},
},
{
id: 2,
name: '马化腾',
email: 'pony.ma@conversation.com',
componentId: 'emailInput',
method: {
name: 'setInputValue',
parameters: {
value: ``,
},
},
},
{
id: 3,
name: '李彦宏',
email: 'robin.li@response.com',
},
{
id: 4,
name: '张一鸣',
email: 'yiming.zhang@example.com',
},
{
id: 5,
name: '王兴',
email: 'xing.wang@widget.org',
componentId: 'root',
method: {
name: 'triggerFetch',
parameters: 'getCustomersQuery',
},
wait: {},
disabled: 'false',
},
];
@ -61,7 +64,16 @@
type: 'core/v1/arrayState',
properties: {
key: 'listData',
initialValue: listdata,
initialValue: [],
},
},
{
type: 'core/v1/fetch',
properties: {
name: 'getCustomersQuery',
url: 'https://61373521eac1410017c18209.mockapi.io/customers',
method: 'get',
headers: [],
},
},
],
@ -91,7 +103,8 @@
id: 'list',
type: 'chakra_ui/v1/list',
properties: {
listData: '{{ root.listData }}',
listData:
'{{ root.getCustomersQuery ? root.getCustomersQuery.data : [] }}',
template: [
{
id: 'listItemTemplate-{{$listItem.id}}',
@ -222,6 +235,16 @@
},
},
traits: [
{
type: 'core/v1/fetch',
properties: {
name: 'deleteUserQuery',
url: 'https://61373521eac1410017c18209.mockapi.io/customers/{{ $listItem.id }}',
method: 'delete',
lazy: true,
onComplete: refresh,
},
},
{
type: 'core/v1/event',
parsedType: {
@ -232,14 +255,10 @@
events: [
{
event: 'click',
componentId: 'root',
componentId: 'listItemDelete-{{$listItem.id}}',
method: {
name: 'deleteItemById',
parameters: {
key: 'listData',
itemIdKey: 'id',
itemId: '{{ $listItem.id }}',
},
name: 'triggerFetch',
parameters: 'deleteUserQuery',
},
wait: {},
disabled: 'false',
@ -324,6 +343,23 @@
},
},
traits: [
{
type: 'core/v1/fetch',
properties: {
name: 'createUserQuery',
url: 'https://61373521eac1410017c18209.mockapi.io/customers',
method: 'post',
headers: [
{ key: 'Content-Type', value: 'application/json' },
],
body: {
name: '{{ nameInput.value }}',
email: '{{ emailInput.value }}',
},
lazy: true,
onComplete: refresh,
},
},
{
type: 'core/v1/event',
parsedType: {
@ -334,22 +370,10 @@
events: [
{
event: 'click',
componentId: 'root',
componentId: 'addButton',
method: {
name: 'setValue',
parameters: {
key: 'listData',
value: `{{
(function() {
let list = root.listData || []
return list.concat({
id: Date.now(),
name: nameInput.value,
email: emailInput.value
})
})()
}}`,
},
name: 'triggerFetch',
parameters: 'createUserQuery',
},
wait: {},
disabled: 'false',
@ -385,6 +409,35 @@
initialValue: '',
},
},
{
type: 'core/v1/fetch',
properties: {
name: 'updateUserQuery',
url: 'https://61373521eac1410017c18209.mockapi.io/customers/{{saveButton.editingId}}',
method: 'put',
headers: [
{ key: 'Content-Type', value: 'application/json' },
],
body: {
name: '{{ nameInput.value }}',
email: '{{ emailInput.value }}',
},
lazy: true,
onComplete: [
...refresh,
{
componentId: 'saveButton',
method: {
name: 'setValue',
parameters: {
key: 'editingId',
value: '-1',
},
},
},
],
},
},
{
type: 'core/v1/event',
parsedType: {
@ -393,63 +446,12 @@
},
properties: {
events: [
{
event: 'click',
componentId: 'root',
method: {
name: 'setValue',
parameters: {
key: 'listData',
value: `{{
(function() {
const list = [...root.listData || []]
let index = list.findIndex((item) => item.id == saveButton.editingId)
list[index] = {
...list[index],
name: nameInput.value,
email: emailInput.value
}
return list
})()
}}`,
},
},
wait: {},
disabled: 'false',
},
{
event: 'click',
componentId: 'saveButton',
method: {
name: 'setValue',
parameters: {
key: 'editingId',
value: '-1',
},
},
wait: {},
disabled: 'false',
},
{
event: 'click',
componentId: 'nameInput',
method: {
name: 'setInputValue',
parameters: {
value: ``,
},
},
wait: {},
disabled: 'false',
},
{
event: 'click',
componentId: 'emailInput',
method: {
name: 'setInputValue',
parameters: {
value: ``,
},
name: 'triggerFetch',
parameters: 'updateUserQuery',
},
wait: {},
disabled: 'false',

View File

@ -1,9 +1,10 @@
import { createTrait } from '@meta-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { globalHandlerMap } from '../../handler';
import { TraitImplementation } from '../../registry';
import { stateStore } from '../../store';
let hasFetched = false;
let hasFetchedMap = new Map<string, boolean>();
const useFetchTrait: TraitImplementation<FetchPropertySchema> = ({
name,
@ -15,7 +16,9 @@ const useFetchTrait: TraitImplementation<FetchPropertySchema> = ({
mergeState,
subscribeMethods,
componentId,
onComplete,
}) => {
// initial data
if (!stateStore[componentId][name]) {
mergeState({
[name]: {
@ -25,19 +28,13 @@ const useFetchTrait: TraitImplementation<FetchPropertySchema> = ({
},
});
}
const hashId = `#${componentId}@${name}`;
const hasFetched = hasFetchedMap.get(hashId);
const lazy = undefined ? method.toLowerCase() !== 'get' : _lazy;
const fetchData = () => {
hasFetched = true;
// before fetching, initial data
mergeState({
[name]: {
loading: true,
data: undefined,
error: undefined,
},
});
// TODO: clear when component destory
hasFetchedMap.set(hashId, true);
// FIXME: listen to the header change
const headers = new Headers();
if (_headers) {
@ -46,11 +43,12 @@ const useFetchTrait: TraitImplementation<FetchPropertySchema> = ({
headers.append(header.key, _headers[i].value);
}
}
// fetch data
fetch(url, {
method,
headers,
body,
body: JSON.stringify(body),
}).then(
async response => {
if (response.ok) {
@ -63,6 +61,12 @@ const useFetchTrait: TraitImplementation<FetchPropertySchema> = ({
error: undefined,
},
});
onComplete?.forEach(event => {
const hanlderMap = globalHandlerMap.get(event.componentId);
if (hanlderMap) {
hanlderMap[event.method.name](event.method.parameters);
}
});
} else {
// TODO: Add FetchError class and remove console info
const error = new Error(
@ -96,16 +100,13 @@ const useFetchTrait: TraitImplementation<FetchPropertySchema> = ({
fetchData();
}
// only subscribe non lazy fetch trait
if (lazy) {
subscribeMethods({
triggerFetch(key) {
if (key === name) {
fetchData();
}
},
});
}
subscribeMethods({
triggerFetch(key) {
if (key === name) {
fetchData();
}
},
});
return {
props: null,
@ -120,6 +121,15 @@ const HeaderPropertySchema = Type.Array(
Type.Object({ key: Type.String(), value: Type.String() })
);
const BodyPropertySchema = Type.Any(); // Type.String()?
const OnCompletePropertySchema = Type.Array(
Type.Object({
componentId: Type.String(),
method: Type.Object({
name: Type.String(),
parameters: Type.Any(),
}),
})
);
type FetchPropertySchema = {
name: Static<typeof NamePropertySchema>;
@ -128,6 +138,7 @@ type FetchPropertySchema = {
lazy?: Static<typeof LazyPropertySchema>;
headers?: Static<typeof HeaderPropertySchema>;
body?: Static<typeof BodyPropertySchema>;
onComplete?: Static<typeof OnCompletePropertySchema>;
};
export default {