ahooks#useRequest TypeScript Examples
The following examples show how to use
ahooks#useRequest.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: hottest-latest.tsx From bext with MIT License | 6 votes |
HottestLatest: FC = () => {
const { latestUpdateList, metaMap } = useMeta();
const { data, error, loading } = useRequest(async () => {
const result = await fetchHottest;
if (result.code !== 200) {
throw new Error(result?.message);
}
return result.data as string[];
});
const hottestMetas = useMemo(() => {
if (!data?.length) {
return [];
}
return take(data.map((id) => metaMap[id]).filter(Boolean), 10);
}, [data, metaMap]);
const renderHottest = () => {
if (loading) {
return <Spinner className="py-4" />;
}
if (error) {
return <div className="py-4 text-center">获取失败...</div>;
}
return <MetaList list={hottestMetas} />;
};
return (
<>
<Title>最近热门</Title>
{renderHottest()}
<Title>最近更新</Title>
<MetaList list={latestUpdateList} />
</>
);
}
Example #2
Source File: db.ts From bext with MIT License | 6 votes |
[DbProvider, useDb] = constate(() => {
const { data: ready } = useRequest(async () => {
try {
await initDb();
return true;
} catch (error) {
return false;
}
});
return { ready: !!ready };
})
Example #3
Source File: meta.tsx From bext with MIT License | 5 votes |
MetaProvider: FC = ({ children }) => {
const { data, loading, error } = useRequest(async () => {
const response = await fetch(config.meta, {
method: 'GET',
});
return await response.json();
});
const { previewId } = usePreview(true);
const value: MetaValue | undefined = useMemo(() => {
if (!data) {
return undefined;
}
const { metas: metaList, latestUpdate } = data.meta;
const metaMap = Object.fromEntries(
metaList.map((meta: Meta) => [meta.id, meta]),
);
const latestUpdateList: any[] = take(
latestUpdate.map((id: string) => metaMap[id]),
3,
);
if (previewId) {
latestUpdateList.unshift({
id: 'preview',
name: '预览脚本',
synopsis: '当前正处于预览模式,请点击预览脚本',
});
}
const { metaTag, hash } = data;
const tagList = metaTag;
const tagMap = Object.fromEntries(
tagList.map((tag: Tag) => [tag.name, tag]),
);
return {
metaList,
metaMap,
latestUpdateList,
tagList,
tagMap,
prefix: `https://cdn.staticaly.com/gh/ikkz/bext-meta@${hash}/public/meta`,
hash,
};
}, [data, previewId]);
const { notify } = useNotifications();
useEffect(() => {
if (previewId) {
notify({
message:
'当前处于预览模式,可前往首页最近更新进入预览,点击左上角图标/前往"开发"退出预览模式',
status: 'info',
});
}
}, [previewId]);
if (loading) {
return <PageLoading />;
}
if (error || !value) {
return <div>出错了...</div>;
}
return <MetaContext.Provider value={value}>{children}</MetaContext.Provider>;
}
Example #4
Source File: config-install.tsx From bext with MIT License | 4 votes |
ConfigInstall: FC<{
onInstall: (build: string) => void;
hide?: () => void;
}> = ({ onInstall, hide }) => {
const { currentMeta } = useMetaDetail();
const [formData, setFormData] = useState(
() => currentMeta?.defaultConfig || {},
);
const [hasError, setHasError] = useState(false);
const { notify } = useNotifications();
const updateConfigCache = useMemoizedFn(() => setConfigCache(formData));
const { run: install, loading } = useRequest(
async (config?: any) => {
const { id, name, version, source, defaultConfig } = currentMeta!;
onInstall(
await excuteCompile({
meta: {
id,
name,
version,
source,
defaultConfig: config ?? defaultConfig,
},
}),
);
hide?.();
},
{
manual: true,
onError: () =>
notify({
message: '编译失败,请点击“更多” -> “报告问题”',
status: 'error',
}),
onSuccess: updateConfigCache,
},
);
const [configCache, setConfigCache] = useLocalStorageState(
bextConfigCacheKey(currentMeta?.id || 'unknown'),
);
const validate = useMemo(() => {
try {
return ajv.compile(currentMeta?.configSchema);
} catch (error) {
console.error(error);
}
}, [currentMeta?.configSchema]);
const restoreCache = () => {
if (validate?.(configCache)) {
setFormData(configCache);
notify({
message: '已填充上次安装选项',
status: 'success',
dismissAfter: 1000,
});
} else {
notify({
message: '选项缓存已过期,请重新编辑配置',
status: 'error',
});
}
};
return (
<Dialog
hidden={false}
onDismiss={hide}
dialogContentProps={{ type: DialogType.normal, title: '安装选项' }}
minWidth={400}
modalProps={{ layerProps: { hostId: LAYER_HOST_ID } }}
>
已为你填充默认选项
{configCache ? (
<>
,或者点击<Link onClick={restoreCache}>恢复之前的安装配置</Link>
</>
) : null}
,你可以直接安装或者修改下方选项后安装。
<Separator />
<JsonSchemaForm
schema={currentMeta?.configSchema}
formData={formData}
onChange={({ formData, errors }) => {
setFormData(formData);
setHasError(!!errors.length);
}}
omitExtraData
liveOmit
liveValidate
>
<></>
</JsonSchemaForm>
<DialogFooter>
<PrimaryButton
onClick={() => install(formData)}
text={loading ? '处理中...' : '安装'}
disabled={hasError || loading}
/>
<DefaultButton onClick={hide} text="取消" />
</DialogFooter>
</Dialog>
);
}
Example #5
Source File: github-login.tsx From bext with MIT License | 4 votes |
GithubLogin: FC = () => {
const [{ code }] = useUrlState({ code: undefined });
const historyReplace = useHistoryReplace();
const { notify, dismissNotification } = useNotifications();
useRequest(
async () => {
const id = uniqueId('login-loading');
notify({
id,
status: 'loading',
message: '登录中',
dismissAfter: 0,
dismissible: false,
});
const response = await fetch(`/api/gh/login?code=${code}`);
const data = await response.json();
if (
response.ok &&
data.code === 200 &&
typeof data?.data?.access_token === 'string'
) {
accessToken$.next(data.data.access_token);
notify({
status: 'success',
message: '登录成功',
});
historyReplace(location.pathname);
trackEvent(Events.ghLoginSuccess);
} else {
notify({
status: 'error',
message:
data?.data?.error_description || data?.msg || response.statusText,
});
}
dismissNotification(id);
},
{
ready: !!code,
refreshDeps: [code],
onError: () => notify({ status: 'error', message: '登录失败' }),
},
);
const el = useObservableState(
useObservable(() =>
octokit$.pipe(
switchMap((octokit) =>
octokit
? user$.pipe(
map(({ status, user }) => {
switch (status) {
case 'complete':
return (
<div className="flex justify-between">
<Persona
imageUrl={user?.avatar_url}
text={user?.name || user?.login}
secondaryText={user?.bio || '暂无签名'}
/>
<Link onClick={() => accessToken$.next(undefined)}>
退出
</Link>
</div>
);
case 'loading':
return '获取用户信息...';
default:
return (
<>
发布、更新脚本请先
<LoginLink />
</>
);
}
}),
startWith('获取用户信息...'),
)
: of(
<>
发布、更新脚本请先
<LoginLink />
</>,
),
),
),
),
null,
);
return (
<>
<Title>Github</Title>
{el}
</>
);
}
Example #6
Source File: install-button.tsx From bext with MIT License | 4 votes |
InstallButton: FC = () => {
const { currentMeta, metaLoading } = useMetaDetail();
const [configVisible, { setTrue: showConfig, setFalse: hideConfig }] =
useBoolean(false);
const installedChecker = useMemoizedFn((): InstallStatus => {
const box = browserMethods.call('installed', currentMeta);
if (box.code === 0) {
return box.result ? 'installed' : 'notinstalled';
}
return 'unknown';
});
const [installStatus, setInstallStatus] = useState(installedChecker);
useInterval(() => {
setInstallStatus(installedChecker);
}, 1000);
const { notify } = useNotifications();
const showUninstall =
installStatus === 'installed' && browserMethods.support('uninstall');
const onUninstall = () => {
trackEvent(Events.metaUninstall, currentMeta?.id);
console.log(
browserMethods.call('uninstall', {
...currentMeta,
author: `bext/${currentMeta?.id}`,
}),
);
};
const onInstall = (build: string) => {
trackEvent(Events.metaInstallSuccess, currentMeta?.id);
console.log(
browserMethods.call('install', {
...currentMeta,
author: `bext/${currentMeta?.id}`,
build,
}),
);
};
const { run: install, loading } = useRequest(
async () => {
const { id, name, version, source, defaultConfig } = currentMeta!;
onInstall(
await excuteCompile({
meta: { id, name, version, source, defaultConfig },
}),
);
},
{
manual: true,
onError: () =>
notify({
message: '编译失败,请点击“更多” -> “报告问题”',
status: 'error',
}),
},
);
return showUninstall ? (
<PrimaryButton
className="ml-2"
onClick={onUninstall}
disabled={metaLoading}
>
卸载
</PrimaryButton>
) : (
<>
<PrimaryButton
className="ml-2"
onClick={currentMeta?.configSchema ? showConfig : install}
text={loading ? '处理中' : '安装此版本'}
disabled={loading || metaLoading}
/>
{configVisible ? (
<ConfigInstall onInstall={onInstall} hide={hideConfig} />
) : null}
</>
);
}
Example #7
Source File: _layout.tsx From bext with MIT License | 4 votes |
MetaLayout: FC = ({ children }) => {
const params = useParams<{ id: string }>();
const { getPreviewMeta } = usePreview();
const { prefix } = useMeta();
const [versions, setVersions] = useState<MetaVersion[]>();
const [currentMeta, setCurrentMeta] = useState<Meta>();
const [currentVersion, setCurrentVersion] = useState<string>();
const { loading: allLoading, error: indexError } = useRequest(
async () => {
if (params.id === 'preview') {
setCurrentMeta(await getPreviewMeta());
} else {
const response = await fetch(`${prefix}/${params.id}/_index.json`);
const metaIndex: MetaIndex = await response.json();
setVersions(metaIndex.versions);
setCurrentMeta(
Object.assign({}, metaIndex.meta, { id: String(params.id) }),
);
setCurrentVersion(metaIndex.versions[0].hash);
}
},
{
refreshDeps: [params.id, getPreviewMeta],
},
);
const {
loading: metaLoading,
run: setVersion,
error: metaError,
} = useRequest(
async (hash: string) => {
setCurrentVersion(hash);
const response = await fetch(`${prefix}/${params.id}/${hash}.json`);
setCurrentMeta({ ...(await response.json()), id: String(params.id) });
},
{ manual: true, refreshDeps: [params.id] },
);
const { notify } = useNotifications();
useEventListener('message', ({ data }) => {
if (
data?.type === 'bext/unknown-install' &&
typeof data?.payload?.build === 'string'
) {
copy(data.payload.build);
notify({
message: '当前浏览器不支持安装,已将脚本内容复制到剪切板',
status: 'info',
});
}
});
if (allLoading) {
return <Spinner size={SpinnerSize.large} className="w-full h-full" />;
}
if (indexError || metaError) {
return (
<div className="w-full h-full flex flex-col items-center justify-center">
出错了...
</div>
);
}
return (
<MetaDetailContext.Provider
value={{
versions,
currentVersion,
setVersion,
currentMeta,
allLoading,
metaLoading,
isPreview: params.id === 'preview',
}}
>
{children}
</MetaDetailContext.Provider>
);
}
Example #8
Source File: dev.tsx From bext with MIT License | 4 votes |
DevScreen: FC = () => {
const [loading, setLoading] = useState(true);
const { params } = useRoute<any>();
const { id, modify } = params || {};
const { data: draft, mutate } = useRequest(
async () => {
try {
return await getDraft(id);
} catch (error) {}
},
{
ready: !!id,
},
);
useUpdateEffect(() => {
if (draft?.id) {
updateUrl(draft.id, draft.url || '');
}
}, [draft?.url, draft?.id]);
const navigation = useNavigation();
useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (loading ? <Text>加载中...</Text> : null),
...(draft?.name ? { title: draft.name } : null),
});
}, [navigation, loading, draft?.name]);
const [modalVisible, setModalVisible] = useState(false);
const { script } = useDebug();
const webView = useRef<WebView>(null);
const onMessage = (msg: string = '{}') => {
try {
const data = JSON.parse(msg);
switch (data.type) {
case 'save':
updateJson(id, JSON.stringify(data.payload));
break;
case 'ready':
webView.current?.injectJavaScript(`
if (window.injectDraft) {
window.injectDraft(decodeURIComponent("${encodeURIComponent(
draft?.json || '{}',
)}"));
}
true;
`);
break;
case 'debug':
setModalVisible(true);
script.current = data.payload;
break;
default:
break;
}
} catch (error) {}
};
const navigateToDebug = () => {
navigation.navigate(
'debug' as never,
{
url: draft?.url,
} as never,
);
setModalVisible(false);
};
return (
<>
<Overlay
transparent
isVisible={modalVisible}
onBackdropPress={() => setModalVisible(false)}
overlayStyle={styles.overlay}
>
<Input
label="输入窗口链接"
value={draft?.url}
onChangeText={(url) => mutate((old) => ({ ...old, url } as any))}
/>
<Button title="确定" disabled={!draft?.url} onPress={navigateToDebug} />
</Overlay>
<WebView
ref={webView}
originWhitelist={['*']}
source={{
uri: `${BEXT_ORIGIN}${
modify
? '/meta?from=dev&devPath=%2Fdev%2Fscript-m'
: '/dev/script-m'
}`,
}}
onLoad={() => setLoading(false)}
onMessage={(e) => onMessage(e.nativeEvent.data)}
/>
</>
);
}
Example #9
Source File: home.tsx From bext with MIT License | 4 votes |
HomeScreen: FC = () => {
const navigation = useNavigation();
const [modalVisible, setModalVisible] = useState(false);
useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<Icon name="add" onPress={() => setModalVisible(true)} />
),
});
}, [navigation]);
const db = useDb();
const { loading, data, run } = useRequest(getDrafts, {
ready: db.ready,
});
const [name, setName] = useState('');
useFocusEffect(useMemoizedFn(run));
const onDelete = useMemoizedFn(async (id: number) => {
await deleteDraft(id);
run();
});
const onPress = useMemoizedFn((id: number) => {
navigation.navigate(
'dev' as never,
{
id,
} as never,
);
});
const createDraft = useMemoizedFn(async (empty: boolean) => {
const id = await addDraft(name);
setName('');
run();
setModalVisible(false);
if (id) {
navigation.navigate(
'dev' as never,
{
id,
modify: empty ? undefined : true,
} as never,
);
}
});
return (
<View style={{ flex: 1 }}>
<Overlay
transparent
isVisible={modalVisible}
onBackdropPress={() => setModalVisible(false)}
overlayStyle={styles.overlay}
>
<Input
label="输入草稿名称(不是脚本名称)"
value={name}
onChangeText={setName}
/>
<View style={styles.buttons}>
<Button
title="创建空白草稿"
disabled={!name.length}
onPress={() => createDraft(true)}
containerStyle={styles.button}
/>
<View style={styles.space} />
<Button
title="从现有脚本创建"
disabled={!name.length}
onPress={() => createDraft(false)}
containerStyle={styles.button}
/>
</View>
</Overlay>
<FlatList
data={data || []}
keyExtractor={(item) => String(item.id)}
renderItem={({ item }) => (
<DraftItem
draft={item}
onDelete={() => onDelete(item.id)}
onPress={() => onPress(item.id)}
/>
)}
onRefresh={run}
refreshing={loading}
/>
</View>
);
}