site: use SWR, make response always fast and reactive (#55186)

* site: use SWR, make query always fast and reactive

* update

* update
This commit is contained in:
lijianan
2025-09-29 23:05:13 +08:00
committed by GitHub
parent 3a2b41c07f
commit ec1be4a9ed
7 changed files with 41 additions and 78 deletions

View File

@@ -1,21 +0,0 @@
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

@@ -1,21 +0,0 @@
import React from 'react';
import fetch from 'cross-fetch';
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 React.use<T>(cache.promise<T>(key, request));
};
export default useFetch;

View File

@@ -138,7 +138,7 @@ const BannerRecommends: React.FC = () => {
const { styles } = useStyle();
const [, lang] = useLocale();
const { isMobile } = React.use(SiteContext);
const data = useSiteData();
const { data } = useSiteData();
const extras = data?.extras?.[lang];
const icons = data?.icons || [];
const first3 =

View File

@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
/* eslint-disable compat/compat */
import { css } from 'antd-style';
import fetch from 'cross-fetch';
import useSWR from 'swr';
export interface Author {
avatar: string;
@@ -82,19 +82,13 @@ export function preLoad(list: string[]) {
}
}
export function useSiteData(): Partial<SiteData> | undefined {
const [data, setData] = useState<SiteData | undefined>(undefined);
useEffect(() => {
fetch('https://render.alipay.com/p/h5data/antd4-config_website-h5data.json').then(
async (res) => {
setData(await res.json());
},
);
}, []);
return data;
}
export const useSiteData = () => {
const { data, error, isLoading } = useSWR<Partial<SiteData>, Error>(
`https://render.alipay.com/p/h5data/antd4-config_website-h5data.json`,
(url: string) => fetch(url).then((res) => res.json()),
);
return { data, error, isLoading };
};
export const getCarouselStyle = () => ({
carousel: css`

View File

@@ -92,7 +92,7 @@ const ArticleList: React.FC<ArticleListProps> = ({ name, data = [], authors = []
);
};
const Articles: React.FC<{ data: Partial<SiteData> }> = ({ data }) => {
const Articles: React.FC<{ data?: Partial<SiteData> }> = ({ data = {} }) => {
const [, lang] = useLocale();
const isZhCN = lang === 'cn';
@@ -145,15 +145,20 @@ const Articles: React.FC<{ data: Partial<SiteData> }> = ({ data }) => {
);
};
export default () => {
const ResourceArticles: React.FC = () => {
const { styles } = useStyle();
const data = useSiteData();
const articles = data ? <Articles data={data} /> : <Skeleton active />;
const { data, error, isLoading } = useSiteData();
if (isLoading) {
return <Skeleton active />;
}
if (error) {
return <div>{error.message}</div>;
}
return (
<div id="articles" className={styles.articles}>
{articles}
<Articles data={data} />
</div>
);
};
export default ResourceArticles;

View File

@@ -3,8 +3,8 @@ import { BugOutlined } from '@ant-design/icons';
import { Button, Drawer, Flex, Grid, Popover, Tag, Timeline, Typography } from 'antd';
import type { TimelineItemProps } from 'antd';
import { createStyles } from 'antd-style';
import useSWR from 'swr';
import useFetch from '../../../hooks/useFetch';
import useLocale from '../../../hooks/useLocale';
import useLocation from '../../../hooks/useLocation';
import { matchDeprecated } from '../../utils';
@@ -212,17 +212,23 @@ const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ cha
const useChangelog = (componentPath: string, lang: 'cn' | 'en'): ChangelogInfo[] => {
const logFileName = `components-changelog-${lang}.json`;
const data = useFetch({
key: `component-changelog-${lang}`,
request: () => import(`../../../preset/${logFileName}`),
});
return React.useMemo(() => {
const component = componentPath.replace(/-/g, '');
const componentName = Object.keys(data).find(
(name) => name.toLowerCase() === component.toLowerCase(),
);
return data[componentName as keyof typeof data] as ChangelogInfo[];
}, [data, componentPath]);
const { data, error, isLoading } = useSWR(
`component-changelog-${lang}`,
() => import(`../../../preset/${logFileName}`),
);
if (error || isLoading) {
return [];
}
const component = componentPath.replace(/-/g, '');
const componentName = Object.keys(data).find(
(name) => name.toLowerCase() === component.toLowerCase(),
);
if (!componentName) {
return [];
}
return data?.[componentName] || [];
};
const ComponentChangelog: React.FC<Readonly<React.PropsWithChildren>> = (props) => {

View File

@@ -232,7 +232,6 @@
"circular-dependency-plugin": "^5.2.2",
"cli-progress": "^3.12.0",
"cross-env": "^10.0.0",
"cross-fetch": "^4.0.0",
"css-tree": "^3.1.0",
"csstree-validator": "^4.0.1",
"cypress-image-diff-html-report": "2.2.0",
@@ -321,6 +320,7 @@
"simple-git": "^3.27.0",
"size-limit": "^11.1.6",
"spinnies": "^0.5.1",
"swr": "^2.3.6",
"tar": "^7.4.3",
"tsx": "^4.20.3",
"typedoc": "^0.28.0",