perf: better async component (#43982)

* perf: better async component

* feat: useFetch

* chore: code clean

* chore: code clean

* chore: fix lint

* type: enhance
This commit is contained in:
MadCcc 2023-08-03 14:45:51 +08:00 committed by GitHub
parent 4da3922a2c
commit d1f8b500df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 83 additions and 42 deletions

View File

@ -1,23 +1,28 @@
export default function use(promise: any) {
if (promise.status === 'fulfilled') {
return promise.value;
export default function use<T>(promise: PromiseLike<T>): T {
const internal: PromiseLike<T> & {
status?: 'pending' | 'fulfilled' | 'rejected';
value?: T;
reason?: any;
} = promise;
if (internal.status === 'fulfilled') {
return internal.value;
}
if (promise.status === 'rejected') {
throw promise.reason;
} else if (promise.status === 'pending') {
throw promise;
if (internal.status === 'rejected') {
throw internal.reason;
} else if (internal.status === 'pending') {
throw internal;
} else {
promise.status = 'pending';
promise.then(
internal.status = 'pending';
internal.then(
(result) => {
promise.status = 'fulfilled';
promise.value = result;
internal.status = 'fulfilled';
internal.value = result;
},
(reason) => {
promise.status = 'rejected';
promise.reason = reason;
internal.status = 'rejected';
internal.reason = reason;
},
);
throw promise;
throw internal;
}
}

View File

@ -0,0 +1,21 @@
export default class FetchCache {
private cache: Map<string, PromiseLike<any>> = new Map();
get(key: string) {
return this.cache.get(key);
}
set(key: string, value: PromiseLike<any>) {
this.cache.set(key, value);
}
promise<T>(key: string, promiseFn: () => PromiseLike<T>): PromiseLike<T> {
const cached = this.get(key);
if (cached) {
return cached;
}
const promise = promiseFn();
this.set(key, promise);
return promise;
}
}

View File

@ -0,0 +1,20 @@
import fetch from 'cross-fetch';
import use from '../use';
import FetchCache from './cache';
const cache = new FetchCache();
const useFetch = <T>(options: string | { request: () => PromiseLike<T>; key: string }) => {
let request;
let key;
if (typeof options === 'string') {
request = () => fetch(options).then((res) => res.json());
key = options;
} else {
request = options.request;
key = options.key;
}
return use(cache.promise<T>(key, request));
};
export default useFetch;

View File

@ -1,6 +1,5 @@
import { css } from 'antd-style';
import fetch from 'cross-fetch';
import use from '../../../hooks/use';
import useFetch from '../../../hooks/useFetch';
export interface Author {
avatar: string;
@ -81,12 +80,8 @@ export function preLoad(list: string[]) {
}
}
const promise = fetch(`https://render.alipay.com/p/h5data/antd4-config_website-h5data.json`).then(
(res) => res.json(),
);
export function useSiteData(): [Partial<SiteData>, boolean] {
return use(promise);
export function useSiteData(): Partial<SiteData> {
return useFetch('https://render.alipay.com/p/h5data/antd4-config_website-h5data.json');
}
export const getCarouselStyle = () => ({

View File

@ -1,9 +1,10 @@
/* eslint-disable global-require */
import React from 'react';
import React, { useMemo } from 'react';
import { createStyles } from 'antd-style';
import { HistoryOutlined } from '@ant-design/icons';
import { Timeline, Button, Drawer, Typography } from 'antd';
import { Button, Drawer, Timeline, Typography } from 'antd';
import useLocale from '../../../hooks/useLocale';
import useFetch from '../../../hooks/useFetch';
const useStyle = createStyles(({ token, css }) => ({
history: css`
@ -85,26 +86,27 @@ function ParseChangelog(props: { changelog: string; refs: string[]; styles: any
}
function useChangelog(componentPath, lang) {
const [list, setList] =
React.useState<{ version: string; changelog: string; refs: string[] }[]>(null);
React.useEffect(() => {
const cnData = require('../../../preset/components-changelog-cn.json');
const enData = require('../../../preset/components-changelog-en.json');
const data = useFetch(
lang === 'cn'
? {
key: 'component-changelog-cn',
request: () => import('../../../preset/components-changelog-cn.json'),
}
: {
key: 'component-changelog-en',
request: () => import('../../../preset/components-changelog-en.json'),
},
);
return useMemo(() => {
const component = componentPath.replace(/-/g, '');
const mergedData = lang === 'cn' ? cnData : enData;
const componentName = Object.keys(mergedData).find(
const componentName = Object.keys(data).find(
(name) => name.toLowerCase() === component.toLowerCase(),
);
const componentChangelog = mergedData[componentName];
setList(componentChangelog || []);
}, [componentPath]);
return list || [];
return data[componentName];
}, [data, componentPath]);
}
export default function ComponentChangelog(props: ComponentChangelogProps) {

View File

@ -1,7 +1,6 @@
import React from 'react';
import type { ComponentChangelogProps } from './ComponentChangelog';
const ComponentChangelog = React.lazy(() => import('./ComponentChangelog'));
import ComponentChangelog from './ComponentChangelog';
export default (props: ComponentChangelogProps) => (
<React.Suspense fallback={null}>

View File

@ -245,7 +245,6 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
/>
)}
</Space>
{pathname.startsWith('/components/') && <ComponentChangelog pathname={pathname} />}
</Typography.Title>
) : null}

View File

@ -1,4 +1,4 @@
/* eslint-disable no-loop-func */
/* eslint-disable no-loop-func, no-console */
// Collect from `changelog.md` to get all components changelog
import path from 'path';
import fs from 'fs-extra';