@gorgonjs/gorgon
Version:
A simple caching library for async functions
243 lines (180 loc) • 6 kB
Markdown
---
name: react
description: >
React integration for @gorgonjs/gorgon via @gorgonjs/react: useGorgon hook
with data/error/loading/refetch state, clearGorgon helper for cache
invalidation from components, cache key management tied to component
lifecycle, and DIY hook patterns. Use when building React components
that need cached async data fetching.
type: framework
library: gorgon
framework: react
library_version: "1.6.0"
requires:
- core
sources:
- "mikevalstar/gorgon:clients/react/index.ts"
- "mikevalstar/gorgon:gorgonjs.dev/src/pages/docs/ui/react.md"
---
This skill builds on `core/SKILL.md`. Read the core skill first for cache key naming, policies, and clearing patterns.
```bash
npm install @gorgonjs/react @gorgonjs/gorgon
```
```typescript
import { useGorgon, clearGorgon } from '@gorgonjs/react';
function UserProfile({ userId }: { userId: string }) {
const { data, error, loading, refetch } = useGorgon(
`user/${userId}`,
() => fetch(`/api/users/${userId}`).then(r => r.json()),
60 * 1000
);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h1>{data.name}</h1>
<button onClick={() => refetch()}>Refresh</button>
</div>
);
}
```
```typescript
const { data, error, loading, refetch } = useGorgon<R>(
key: string,
asyncFunc: () => Promise<R>,
policy?: GorgonPolicyInput,
options?: { debug?: boolean }
);
```
Returns:
- `data: R | null` — resolved data, null while loading
- `error: Error | null` — error if the async function threw
- `loading: boolean` — true while fetching
- `refetch(opts?: { clearKey?: string }): void` — clears cache key and re-fetches
The hook re-fetches when `key` changes. Include all dynamic parameters in the key.
```typescript
import { clearGorgon } from '@gorgonjs/react';
clearGorgon('user/*'); // clear keys matching pattern
clearGorgon(); // clear all cached data
```
```typescript
const { data, refetch } = useGorgon(
`user/${userId}`,
() => fetchUser(userId),
60000
);
// Clear just this key and re-fetch
const handleRefresh = () => refetch();
// Clear all user keys and re-fetch this one
const handleClearAll = () => refetch({ clearKey: 'user/*' });
```
```typescript
import { useGorgon } from '@gorgonjs/react';
interface Todo { id: number; title: string; completed: boolean; }
function TodoItem({ id }: { id: number }) {
const { data, loading } = useGorgon<Todo>(
`todo/${id}`,
() => fetch(`/api/todos/${id}`).then(r => r.json()),
30000
);
if (loading || !data) return <span>Loading...</span>;
return <span>{data.title}</span>;
}
```
```typescript
function EditUser({ userId }: { userId: string }) {
const { data, refetch } = useGorgon(
`user/${userId}`,
() => fetchUser(userId),
60000
);
const handleSave = async (formData: UserUpdate) => {
await updateUser(userId, formData);
refetch(); // clears cache and re-renders with fresh data
};
return <UserForm data={data} onSave={handleSave} />;
}
```
```typescript
import { useState, useEffect } from 'react';
import Gorgon, { GorgonPolicyInput } from '@gorgonjs/gorgon';
function useGorgon<R>(
key: string,
asyncFunc: () => Promise<R>,
policy?: GorgonPolicyInput
): R | null {
const [data, setData] = useState<R | null>(null);
useEffect(() => {
let mounted = true;
Gorgon.get(key, asyncFunc, policy)
.then(result => { if (mounted) setData(result); })
.catch(err => console.error('Gorgon error', err));
return () => { mounted = false; };
}, [key]);
return data;
}
```
Wrong:
```typescript
const { data } = useGorgon('user-profile', () => fetchUser(userId), 60000);
```
Correct:
```typescript
const { data } = useGorgon(`user/${userId}`, () => fetchUser(userId), 60000);
```
`useGorgon` re-fetches when the key changes. If dynamic parameters are not in the key, changing `userId` returns stale data from the previous user.
Source: documentation — react
Wrong:
```typescript
const { data } = useGorgon('user/1', fetchUser, 60000);
const handleUpdate = async () => {
await updateUser(1, newData);
Gorgon.clear('user/1'); // cache is cleared but component doesn't re-render
};
```
Correct:
```typescript
const { data, refetch } = useGorgon('user/1', fetchUser, 60000);
const handleUpdate = async () => {
await updateUser(1, newData);
refetch(); // clears cache AND triggers re-render
};
```
`Gorgon.clear()` removes the cached value but does not trigger a React re-render. Use `refetch()` from the hook to clear and re-fetch in one step.
Source: documentation — react
Wrong:
```typescript
useEffect(() => {
Gorgon.get(key, asyncFunc, policy).then(setData);
}, [key]);
```
Correct:
```typescript
useEffect(() => {
let mounted = true;
Gorgon.get(key, asyncFunc, policy)
.then(result => { if (mounted) setData(result); });
return () => { mounted = false; };
}, [key]);
```
Without the mounted guard, setting state after unmount causes React warnings and potential bugs with rapid navigation.
Source: documentation — react
When using `useGorgon`, the same tension from core caching applies in the UI: long TTLs show stale data to users, short TTLs cause excessive re-fetching and loading spinners. Pair appropriate TTLs with explicit `refetch()` calls on user-initiated mutations.
See also: `core/SKILL.md` § Common Mistakes
Targets @gorgonjs/react with @gorgonjs/gorgon v1.6.0.