Skip to main content

useCache()

Data rendering without the fetch.

General purpose store access can be useful when the data's existance is of interest (like if a user is authenticated), or general purpose store access like Query

Usage

Fixtures
GET /user
{"id":"777","name":"Albatras","isAdmin":true}
api/User
export class User extends Entity {
id = '';
name = '';
isAdmin = false;
pk() {
return this.id;
}
}
export const UserResource = {
...createResource({
path: '/users/:id',
schema: User,
}),
current: new RestEndpoint({
path: '/user',
schema: User,
}),
};
NotAuthorized
import { useLoading } from '@rest-hooks/hooks';
import { UserResource } from './api/User';
export default function NotAuthorized() {
const ctrl = useController();
const [handleLogin, loading] = useLoading((e: any) => {
e.preventDefault();
return ctrl.fetch(UserResource.current);
}, []);
return (
<div>
<p>Not authorized</p>
{loading ? (
'logging in...'
) : (
<a href="#" onClick={handleLogin}>
Login
</a>
)}
</div>
);
}
AuthorizedUserOnlyControls
import { User } from './api/User';
export default function AuthorizedUserOnlyControls({ user }: { user: User }) {
const ctrl = useController();
const handleLogout = (e: any) => {
e.preventDefault();
return ctrl.invalidate(UserResource.current);
};
return (
<div>
<p>Welcome, {user.name}!</p>
<a href="#" onClick={handleLogout}>
Logout
</a>
</div>
);
}
AuthorizedPage
import { UserResource } from './api/User';
import NotAuthorized from './NotAuthorized';
import AuthorizedUserOnlyControls from './AuthorizedUserOnlyControls';
function AuthorizedPage() {
// currentUser as User | undefined
const currentUser = useCache(UserResource.current);
// user is not logged in
if (!currentUser) return <NotAuthorized />;
// currentUser as User (typeguarded)
return <AuthorizedUserOnlyControls user={currentUser} />;
}
render(<AuthorizedPage />);
Live Preview
Loading...
Store

See truthiness narrowing for more information about type handling

Behavior

Expiry StatusReturnsConditions
Invalidundefinednot in store, deletion, invalidation, invalidIfStale
Staledenormalized(first-render, arg change) & expiry < now
Validdenormalizedfetch completion
undefinednull used as second argument
Conditional Dependencies

Use null as the second argument on any rest hooks to indicate "do nothing."

// todo could be undefined if id is undefined
const todo = useCache(TodoResource.get, id ? { id } : null);

Types

function useCache(
endpoint: ReadEndpoint,
...args: Parameters<typeof endpoint> | [null]
): Denormalize<typeof endpoint.schema> | null;

Examples

Query arbitrary Entities

Query provides programmatic access to the Rest Hooks store.

Fixtures
GET /users
[{"id":"123","name":"Jim"},{"id":"456","name":"Jane"},{"id":"777","name":"Albatras","isAdmin":true}]
api/User.ts
export class User extends Entity {
id = '';
name = '';
isAdmin = false;
pk() {
return this.id;
}
}
export const UserResource = createResource({
path: '/users/:id',
schema: User,
});
UsersPage.tsx
import { Query, schema } from '@rest-hooks/rest';
import { UserResource, User } from './api/User';
const sortedUsers = new Query(
new schema.All(User),
(entries, { asc } = { asc: false }) => {
const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
if (asc) return sorted;
return sorted.reverse();
},
);
function UsersPage() {
useFetch(UserResource.getList);
const users = useCache(sortedUsers, { asc: true });
if (!users) return <div>No users in cache yet</div>;
return (
<div>
{users.map(user => (
<div key={user.pk()}>{user.name}</div>
))}
</div>
);
}
render(<UsersPage />);
Live Preview
Loading...
Store

Todo App

Explore more Rest Hooks demos