From d215b4a566d7390d0f53880665239c790f7c07a8 Mon Sep 17 00:00:00 2001 From: Viki Date: Thu, 20 Jun 2024 11:42:03 +0800 Subject: [PATCH] docs: modify demos --- src/use-async-effect/index.mdx | 12 ++++++--- src/use-async-effect/index.ts | 2 +- src/use-async-fn/index.mdx | 4 +-- src/use-async-lock/demo.tsx | 3 ++- src/use-async-lock/index.mdx | 20 +++++++------- src/use-async-lock/index.ts | 19 ++++++++----- src/use-async-update-effect/demo.tsx | 27 ++++++------------- src/use-before-unload/index.mdx | 2 +- src/use-mouse-in-element/demo.tsx | 5 +++- src/utils/create-effect/async.ts | 13 ++++++--- src/utils/create-effect/update.ts | 4 +-- website/docs/features/ref-getter.md | 4 +++ .../src/components/doc-related/raw-code.tsx | 2 +- website/src/components/doc-related/source.tsx | 27 ++++++++++--------- 14 files changed, 81 insertions(+), 63 deletions(-) diff --git a/src/use-async-effect/index.mdx b/src/use-async-effect/index.mdx index a43e7db2..f0adf438 100644 --- a/src/use-async-effect/index.mdx +++ b/src/use-async-effect/index.mdx @@ -30,12 +30,18 @@ import { Source } from '@/components' ## API ```tsx -useAsyncEffect(callback, deps?) +useAsyncEffect(asyncCallback, deps) ``` -### Callback +### AsyncCallback -Same as [React.useEffect](https://react.dev/reference/react/useEffect). +A effect callback, support **async** function. + +```tsx +export type AsyncEffectCallback = (isCancelled: () => boolean) => void + +export type UseAsyncEffectCallback = AsyncEffectCallback +``` ### Deps diff --git a/src/use-async-effect/index.ts b/src/use-async-effect/index.ts index 9e5c5685..22a37a0c 100644 --- a/src/use-async-effect/index.ts +++ b/src/use-async-effect/index.ts @@ -3,7 +3,7 @@ import { createAsyncEffect } from '../utils/create-effect/async' import type { AsyncEffectCallback } from '../utils/create-effect/async' -export interface UseAsyncEffectCallback extends AsyncEffectCallback {} +export type UseAsyncEffectCallback = AsyncEffectCallback /** * like `React.useEffect` but it's can accept an `async` function diff --git a/src/use-async-fn/index.mdx b/src/use-async-fn/index.mdx index ac13658d..ce229a4a 100644 --- a/src/use-async-fn/index.mdx +++ b/src/use-async-fn/index.mdx @@ -35,9 +35,7 @@ const { run, loading, value, error } = useAsyncFn(asyncFn, options) ### AsyncFn -```tsx -export type AsyncFn = (...args: any[]) => Promise -``` +A function that returns a promise. ### Options diff --git a/src/use-async-lock/demo.tsx b/src/use-async-lock/demo.tsx index 8a439116..4664bd4b 100644 --- a/src/use-async-lock/demo.tsx +++ b/src/use-async-lock/demo.tsx @@ -8,9 +8,10 @@ export function App() { const fetchData = useAsyncFn(async () => { await mockFetch(300) setData(OTP()) + return OTP() }) - const lockedFetchData = useAsyncLock(fetchData.run, () => countActions.inc()) + const lockedFetchData = useAsyncLock(fetchData.run, countActions.inc) return ( diff --git a/src/use-async-lock/index.mdx b/src/use-async-lock/index.mdx index 72fa207a..0316299c 100644 --- a/src/use-async-lock/index.mdx +++ b/src/use-async-lock/index.mdx @@ -30,23 +30,25 @@ import { Source } from '@/components' ## API ```tsx -const lockedFn = useAsyncLock(fn, onMeetLock) +const lockedFn = useAsyncLock(asyncFn, onMeetLock) ``` -### Fn +### AsyncFn -```tsx -export type Fn = (...args: any[]) => Promise -``` +A function that returns a promise. ### OnMeetLock -```tsx -export type onMeetLock = () => void -``` +A function that will be called when the function is locked and is called again. ### Returns +A function that can be used to ensure that **only one is running at a time**, return a promise that resolves the return value of the async function or the return value of the invalid operation callback function. + ```tsx -export type lockedFn = (...args: T) => Promise> +export type UseAsyncLockReturn = ( + ...args: Parameters +) => R extends undefined + ? Promise> | undefined> + : Promise> | Awaited>>Promise> ``` diff --git a/src/use-async-lock/index.ts b/src/use-async-lock/index.ts index d91cb5c7..b21c8d83 100644 --- a/src/use-async-lock/index.ts +++ b/src/use-async-lock/index.ts @@ -1,19 +1,24 @@ -import { useRef } from 'react' +import { useGetterRef } from '../use-getter-ref' import { useLatest } from '../use-latest' import { useStableFn } from '../use-stable-fn' import type { AnyFunc } from '../utils/basic' -export function useAsyncLock(asyncFn: T, onMeetLock?: () => void): T { - const isLockedRef = useRef(false) +export type UseAsyncLockReturn = ( + ...args: Parameters +) => R extends undefined + ? Promise> | undefined> + : Promise> | Awaited>> + +export function useAsyncLock(asyncFn: T, onMeetLock?: R) { + const [isLockedRef, isLocked] = useGetterRef(false) const latest = useLatest({ asyncFn, onMeetLock }) const lockedAsync = useStableFn(async (...args: Parameters) => { const { asyncFn, onMeetLock } = latest.current - if (isLockedRef.current) { - onMeetLock?.() - return + if (isLocked()) { + return onMeetLock?.() } isLockedRef.current = true @@ -25,5 +30,5 @@ export function useAsyncLock(asyncFn: T, onMeetLock?: () => v } }) - return lockedAsync as T + return lockedAsync as UseAsyncLockReturn } diff --git a/src/use-async-update-effect/demo.tsx b/src/use-async-update-effect/demo.tsx index 6c3d9575..1d4b05e3 100644 --- a/src/use-async-update-effect/demo.tsx +++ b/src/use-async-update-effect/demo.tsx @@ -1,29 +1,16 @@ -import { Button, Card, KeyValue, Zone } from '@/components' +import { Button, Card, KeyValue } from '@/components' import { useAsyncUpdateEffect, useCounter, useToggle } from '@shined/react-use' -import type { SetIntervalReturn } from '../utils/basic' - export function App() { - const [show, toggle] = useToggle(true) - - return ( - - - {show && } - - ) -} - -function Count() { const [status, toggle] = useToggle(false) const [count, actions] = useCounter(0) // biome-ignore lint/correctness/useExhaustiveDependencies: for demo useAsyncUpdateEffect( async (isCancelled) => { - const timer: SetIntervalReturn = window.setInterval(() => { + const timer = setInterval(() => { // use `isCancelled()` to check if the effect is cancelled (unmount). - if (isCancelled()) return window.clearInterval(timer) + if (isCancelled()) return clearInterval(timer) // safely do something when component is not unmount. actions.inc(1) }, 1000) @@ -32,9 +19,11 @@ function Count() { ) return ( - + - - +
+ +
+
) } diff --git a/src/use-before-unload/index.mdx b/src/use-before-unload/index.mdx index 7b5ab63d..8e9c7544 100644 --- a/src/use-before-unload/index.mdx +++ b/src/use-before-unload/index.mdx @@ -38,7 +38,7 @@ useBeforeUnload(callback, options) A function that will be called right before the page is potentially unloaded. ```tsx -export type Callback = (e: BeforeUnloadEvent) => void +export type UseBeforeUnloadCallback = (e: BeforeUnloadEvent) => void ``` ### Options diff --git a/src/use-mouse-in-element/demo.tsx b/src/use-mouse-in-element/demo.tsx index 318072f8..3e6af34a 100644 --- a/src/use-mouse-in-element/demo.tsx +++ b/src/use-mouse-in-element/demo.tsx @@ -19,7 +19,10 @@ export function App() { -
+
) } diff --git a/src/utils/create-effect/async.ts b/src/utils/create-effect/async.ts index 09477dd7..7fd1bb16 100644 --- a/src/utils/create-effect/async.ts +++ b/src/utils/create-effect/async.ts @@ -1,3 +1,6 @@ +import { useGetterRef } from '../../use-getter-ref' +import { useLatest } from '../../use-latest' + import type { DependencyList } from 'react' import type { ExtendedReactEffect } from '../basic' @@ -5,12 +8,16 @@ export type AsyncEffectCallback = (isCancelled: () => boolean) => void export function createAsyncEffect(effect: ExtendedReactEffect) { return (callback: AsyncEffectCallback, deps?: DependencyList, ...args: T[]): void => { + const [isCancelledRef, isCancelled] = useGetterRef(false) + const latest = useLatest({ callback }) + effect( () => { - let cancelled = false - callback(() => cancelled) + isCancelledRef.current = false + latest.current.callback(isCancelled) + return () => { - cancelled = true + isCancelledRef.current = true } }, deps, diff --git a/src/utils/create-effect/update.ts b/src/utils/create-effect/update.ts index 24cc5e02..42c219cb 100644 --- a/src/utils/create-effect/update.ts +++ b/src/utils/create-effect/update.ts @@ -10,7 +10,7 @@ export function createUpdateEffect(effect: ExtendedReactEffect) return (callback: () => void, deps?: DependencyList, ...args: T[]): void => { const isActualUpdate = useRef(false) - const latestCallback = useLatest(callback) + const latest = useLatest({ callback }) effectOnce( () => { @@ -26,7 +26,7 @@ export function createUpdateEffect(effect: ExtendedReactEffect) if (!isActualUpdate.current) { isActualUpdate.current = true } else { - return latestCallback.current() + return latest.current.callback() } }, deps, diff --git a/website/docs/features/ref-getter.md b/website/docs/features/ref-getter.md index 9c71cc48..2c171646 100644 --- a/website/docs/features/ref-getter.md +++ b/website/docs/features/ref-getter.md @@ -51,6 +51,10 @@ console.log(isActive) // Outputs: true It is a ref getter created by `usePausable`, see [Pausable](/docs/features/pausable) for more details. +### `isCancelled` {#is-cancelled} + +It is a ref getter params in `useAsyncEffect` callback, see [useAsyncEffect](/reference/use-async-effect) for more details. + ### `isMounted` {#is-mounted} It is a ref getter created by `useMounted`, see [useMounted](/reference/use-mounted) for more details. diff --git a/website/src/components/doc-related/raw-code.tsx b/website/src/components/doc-related/raw-code.tsx index 931b162b..2b195e86 100644 --- a/website/src/components/doc-related/raw-code.tsx +++ b/website/src/components/doc-related/raw-code.tsx @@ -1,5 +1,5 @@ -import CodeBlock from '@theme/CodeBlock' import { useToggle } from '@site/../src' +import CodeBlock from '@theme/CodeBlock' import { Button } from '../demo-related' const ignores = ['prettier-ignore', 'biome-ignore'] diff --git a/website/src/components/doc-related/source.tsx b/website/src/components/doc-related/source.tsx index 651150a4..2db627a9 100644 --- a/website/src/components/doc-related/source.tsx +++ b/website/src/components/doc-related/source.tsx @@ -19,18 +19,21 @@ export function Source({ name, tsx }: SourceProps) { ].map((item) => ({ ...item, url: `${url}/${item.path}` })) return ( -
- {list.map((item) => ( - - {item.name} - - ))} +
+

Click links below to view source on GitHub.

+
+ {list.map((item) => ( + + {item.name} + + ))} +
) }