Skip to content

Commit

Permalink
Update README, version, and enhance components with new features and …
Browse files Browse the repository at this point in the history
…improved styling
  • Loading branch information
HK-SHAO committed Feb 6, 2025
1 parent cfc80d6 commit 6cf9dc7
Show file tree
Hide file tree
Showing 14 changed files with 137 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ npm i react-client-async
You can use the `useAsync` hook to create a task.

```tsx
console.log(useAsync(fn, args, options));
console.log(useAsync(promiseFn, args, options));
```


Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-client-async",
"version": "1.3.3",
"version": "1.3.4",
"main": "dist/lib.js",
"module": "dist/lib.js",
"files": ["dist/", "README.md", "LICENSE"],
Expand All @@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/HK-SHAO/react-client-async.git"
},
"description": "React tools for async rendering in client side.",
"description": "React tools for async rendering in client side! 🚀",
"readme": "README.md",
"keywords": [
"react",
Expand Down
35 changes: 31 additions & 4 deletions src/libs/components/DemoPage.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import RecursiveAsyncDemo from '#components/RecursiveAsyncDemo';
import UseAsyncMemoDemo from '#components/UseAsyncMemoDemo';
import LatestVersion from '#components/LatestVersion';
import UseAsyncDemo from '#components/UseAsyncDemo';
import AsyncDemo from '#components/AsyncDemo';
import LatestVersion from './LatestVersion';
import Footer from "#components/Footer";
import Title from "#components/Title";
import Card from "#components/Card";

import { description } from '#src/../package.json';

import { toast } from 'react-toastify';

<div className='w-full flex justify-center -mb-6 -mt-4'>
Expand All @@ -15,7 +18,7 @@ import { toast } from 'react-toastify';
# <Title/>

<div className="w-full text-center -mt-8 mb-10 p-0">
<p className='m-0 p-0 text-base/snug text-gray-500 font-bold'>Easy to use async function in React components! 🚀</p>
<p className='m-0 p-0 text-base/snug text-gray-500 font-bold'>{description}</p>
</div>

<div className='w-full flex justify-center -mt-4'>
Expand Down Expand Up @@ -57,7 +60,7 @@ npm i react-client-async
You can use the `useAsync` hook to create a task.

```tsx
console.log(useAsync(fn, args, options));
console.log(useAsync(promiseFn, args, options));
```

<UseAsyncDemo />
Expand Down Expand Up @@ -85,7 +88,7 @@ You can use the `Async` to render an async component.

<Card className='mt-10 pb-8'>

## <a href="#RecursiveDemo" id="RecursiveDemo">🎬 `Demo` of Recursive Async Component</a>
## <a href="#RecursiveDemo" id="RecursiveDemo">🎬 Recursive Async Component Demo</a>

Easy to `wrap` a recursive async component and memoize it.

Expand All @@ -108,6 +111,30 @@ const Rec: FC<{ n: number }> = wrap(
</Card>


<Card className='mt-10 pb-8'>

## <a href='#useAsyncMemo' id="useAsyncMemo">✅ `useAsyncMemo` Hook</a>

Use the `useAsyncMemo` hook to create a memoized async task.

```tsx
const {
state: { result, pending, error },
load, stop
} = useAsyncMemo(
async ({ signal }) =>
fetch("/package.json", { signal })
.then((res) => res.json()),
[/* Function Dependencies */],
{ autoLoad: false },
);
```

<UseAsyncMemoDemo/>

</Card>


<Card className='mt-10 pb-2 mb-10'>

## <a href='#Next' id="Next">⏳ What is Next?</a>
Expand Down
10 changes: 7 additions & 3 deletions src/libs/components/LatestVersion.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useCallback } from 'react';
import { useAsyncMemo } from '#src/lib';

import delayWithSignal from '../utils/delayWithSignal';
import packageJsonUrl from '#constants/packageJsonUrl';
import delayWithSignal from '#utils/delayWithSignal';

type PackageJson = typeof import('#src/../package.json');

export default function LatestVersion() {
const {
Expand All @@ -11,8 +14,9 @@ export default function LatestVersion() {
} = useAsyncMemo(
async ({ signal }) => {
const [ret] = await Promise.all([
// ToDo: Dynamic import with signal
import('#constants/version').then((m) => m.default),
fetch(packageJsonUrl, { signal })
.then((res) => res.json())
.then((data: PackageJson) => data.version),
// Avoid too fast loading
delayWithSignal(400, signal),
]);
Expand Down
2 changes: 1 addition & 1 deletion src/libs/components/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const title = 'React Async for Client';
export default function Title() {
return (
<>
<div className="relative w-full h-auto font-bold scale-100 hover:scale-130 transition-transform">
<div className="relative w-full h-auto font-bold scale-100 hover:scale-110 transition-transform">
<div className="inset-0 flex justify-center items-center bg-clip-text blur-2xl py-4 w-full text-7xl text-center text-transparent pointer-events-none select-none gradient-bg">
{title}
</div>
Expand Down
19 changes: 3 additions & 16 deletions src/libs/components/UseAsyncDemo.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import { type RefObject, useCallback, useRef } from 'react';

import { useAsync } from 'react-client-async';
import { ObjectInspector, chromeDark } from 'react-inspector';
import { ObjectInspector } from 'react-inspector';
import { toast } from 'react-toastify';
import inspectorTheme from '#constants/inspectorTheme';
import delayWithSignal from '#utils/delayWithSignal';

const inspectorTheme: typeof chromeDark = {
...chromeDark,
...{
BASE_BACKGROUND_COLOR: 'transparent',
BASE_FONT_SIZE: 'var(--text-sm)',
ARROW_FONT_SIZE: 'var(--text-sm)' as unknown as number,
TREENODE_FONT_SIZE: 'var(--text-sm)',
},
};

const abortedByStop = Symbol('Aborted By Stop');

const fetchSome = async (
Expand Down Expand Up @@ -46,11 +37,7 @@ export default function UseAsyncDemo() {
className="flex flex-col justify-center items-center gap-2 py-4 p-2 rounded-md prose-pre"
style={{ textShadow: 'rgba(0, 0, 0, 0.3) 0px 1px' }}
>
<ObjectInspector
data={task}
expandLevel={3}
theme={inspectorTheme as unknown as 'chromeDark'}
/>
<ObjectInspector data={task} expandLevel={3} theme={inspectorTheme} />

<div className="bg-gray-500/10 m-2 py-[0.5px] w-full" />
<div className="flex gap-4 w-[24em]">
Expand Down
69 changes: 69 additions & 0 deletions src/libs/components/UseAsyncMemoDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { ObjectInspector } from 'react-inspector';
import inspectorTheme from '#constants/inspectorTheme';
import packageJsonUrl from '#constants/packageJsonUrl';
import { useAsyncMemo } from '#src/lib';
import delayWithSignal from '../utils/delayWithSignal';

type PackageJson = typeof import('#src/../package.json');

const whiteList = ['name', 'version', 'author', 'license', 'homepage'];
const whiteListSet = new Set(whiteList);

export default function UseAsyncMemoDemo() {
const {
state: { result, pending, error },
load,
stop,
} = useAsyncMemo(
async ({ signal }) =>
delayWithSignal(200, signal)
.then(() => fetch(packageJsonUrl, { signal }))
.then((res) => res.json() as Promise<PackageJson>),
[
/* No dependencies */
],
{ autoLoad: false },
);

const newResult =
result && typeof result === 'object'
? Object.fromEntries(
Object.entries(result).filter(([key]) => whiteListSet.has(key)),
)
: result;

const data = { result: newResult, pending, error };

return (
<>
<div
className="flex flex-col justify-center items-center gap-2 py-4 p-2 rounded-md prose-pre"
style={{ textShadow: 'rgba(0, 0, 0, 0.3) 0px 1px' }}
>
<div className="w-full">
<ObjectInspector data={data} expandLevel={3} theme={inspectorTheme} />
</div>

<div className="bg-gray-500/10 m-2 py-[0.5px] w-full" />
<div className="flex gap-4 w-[24em]">
<button
type="button"
className="flex-1 text-base btn btn-blue"
onClick={load}
disabled={pending}
>
{pending ? 'Loading...' : 'Load'}
</button>
<button
type="button"
className="flex-1 text-base btn btn-red"
onClick={stop}
disabled={!pending}
>
Stop
</button>
</div>
</div>
</>
);
}
13 changes: 13 additions & 0 deletions src/libs/constants/inspectorTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { chromeDark } from 'react-inspector';

const inspectorTheme: typeof chromeDark = {
...chromeDark,
...{
BASE_BACKGROUND_COLOR: 'transparent',
BASE_FONT_SIZE: 'var(--text-sm)',
ARROW_FONT_SIZE: 'var(--text-sm)' as unknown as number,
TREENODE_FONT_SIZE: 'var(--text-sm)',
},
};

export default inspectorTheme as unknown as 'chromeDark';
3 changes: 3 additions & 0 deletions src/libs/constants/packageJsonUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const packageJsonUrl = new URL('../../../package.json', import.meta.url).href;

export default packageJsonUrl;
2 changes: 1 addition & 1 deletion src/libs/constants/version.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { version } from '../../../package.json';
import { version } from '#src/../package.json';

export default version;
4 changes: 3 additions & 1 deletion src/libs/hooks/useAsyncMemo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ import { type DependencyList, useMemo } from 'react';
import useAsync, {
type UseAsyncFn,
type UseAsyncFnExtras,
type UseAsyncOptions,
} from '#hooks/useAsync';

export default function useAsyncMemo<T>(
promiseFn: (extras: UseAsyncFnExtras) => Promise<T>,
deps: DependencyList,
options: UseAsyncOptions<null> = {},
) {
// biome-ignore lint/correctness/useExhaustiveDependencies: only deps are needed
const fn = useMemo<UseAsyncFn<null, T>>(
() => (_, extras) => promiseFn(extras),
deps,
);
return useAsync(fn, null);
return useAsync(fn, null, options);
}
2 changes: 1 addition & 1 deletion src/libs/utils/isAsyncFunction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AsyncFunction } from '../constants/basic';
import { AsyncFunction } from '#constants/basic';

/**
* Check if the function is an async function.
Expand Down
2 changes: 1 addition & 1 deletion src/libs/utils/isReactMemo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { MemoComponent } from '../types/react';
import type { MemoComponent } from '#types/react';

/**
* Check if the value is a React memo component.
Expand Down
2 changes: 1 addition & 1 deletion src/libs/utils/sameProps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { propsAreEqual } from '../types/react';
import type { propsAreEqual } from '#types/react';

/**
* Check if the props are the same.
Expand Down

0 comments on commit 6cf9dc7

Please sign in to comment.