Using hooks with class components
Hooks are great, but many of us are working with existing codebases or libraries with class based components. Some might be easy to migrate but others might be more diffcult. Should this block you from adopting Reactive Data Client? Of course not!
Using the simple hook-hoc interop library we can create Higher Order Components from hooks quite easily. This enables us to easily replace any existing HOC with ease.
Install hook-hoc
- NPM
- Yarn
- pnpm
- esm.sh
yarn add hook-hoc
npm install --save hook-hoc
pnpm add hook-hoc
<script type="module">
import * from 'https://esm.sh/hook-hoc';
</script>
Use with class
import withHook from 'hook-hoc';
import { useSuspense } from '@data-client/react';
import UserResource from 'resources/user';
class Profile extends React.PureComponent<{
id: number;
user: UserResource;
friends: UserResource[];
}> {
//...
}
export default withHook(({ id }: { id: number }) => {
const [user, friends] = useSuspense(
[UserResource.get, { id }],
[UserResource.getList, { friendid: id }],
);
return { user, friends };
})(Profile);
Here you can see the return value of the function you pass in gets injected into the props of the component you wrap.
Extracting the function
You might notice the function we pass to withHook()
is a function that calls
hooks. That makes it a hook by definition. To make this detectable by the rules of hooks
and also potentially reusable, let's move it out to a named function:
import withHook from 'hook-hoc';
import { useSuspense } from '@data-client/react';
import UserResource from 'resources/user';
function useProfile({ id }: { id: number }) {
const [user, friends] = useSuspense(
[UserResource.get, { id }],
[UserResource.getList, { friendid: id }],
);
return { user, friends };
}
class Profile extends React.PureComponent<{
id: number;
user: UserResource;
friends: UserResource[];
}> {
//...
}
export default withHook(useProfile)(Profile);
Filters, debounce and more
Often times you'll be doing a bit more than just retrieving the data. We can do all of that extra work in the hook we just created. Here we'll add some client-side filtering as well as debouncing the requests themselves.
You can combine any hooks here - the sky's the limit.
import { useSuspense } from '@data-client/react';
import UserResource from 'resources/user';
function useProfile({ id }: { id: number }) {
const debouncedId = useDebounce(id, 150);
const [user, friends] = useSuspense(
[UserResource.get, { id }],
[UserResource.getList, { friendid: id }],
);
const realFriends = friends.filter(friend => friend.isReal);
return { user, friends: realFriends };
}
// rest of file...