I have a component like the following:
const Dashboard = () => {
// hook specific to the component
const { data, loading, error } = useGetDashboardDataQuery();
// rendering that I would like to extract into a HOC
if (loading) return <Loader />;
if (error) return <Error />;
// rendering specific to the component
if (data) {
return <h2>{data.dashboard_title}</h2>;
}
return null;
};
I would like for my loading/error handling to not be specific to this particular component, so I can reuse it with other components.
So my initial idea was to use a HOC (higher-order-component). However, the HOC has no concept of my useGetDashboardDataQuery
, and I cannot pass them in because the HOC is handled at compile time, ex:
class Dashboard = () => {
const { data, loading, error } = useGetDashboardDataQuery();
...
}
export default withLoader(Dashboard); // cannot pass loading/error here
From reading the documentation, it is suggested to lift up the state. But since my useGetDashboardDataQuery
hook is specific to the component, I'm not sure how to do this in an abstract way.
Another suggestion I was given was to use render props but I am having a hard time applying it to this use case.
I come from a PHP background so still learning to do these things in an idiomatic functional react way. Thank you for your patience!
CodePudding user response:
I suggest that you create a condtional wrapper component which takes data
, error
and loading
as props in some form. It will check these values and return the children if data should be displayed.
This is how you would use it in any component:
return (
<LoaderHandler data={data} error={error} loading={loading}>
<h2>{data?.dashboard_title}</h2>
</LoaderHandler>
);
And the wrapper would look something like this:
// i don't know what library (if any) you're using to fetch data,
// so not sure about the correct types here.
type Props = {
children: ReactNode;
data: ?;
error?: ?;
loading: boolean;
};
const LoaderHandler = ({children, data, error, loading}: Props): JSX.Element | null => {
if (loading) return <Loader />;
if (error) return <Error />;
if (!data) return null;
return children;
};
One caveat: typescript will complain if you try to use data.dashboard_title
because data
might be undefined or null. You can replace it with data?.dashboard_title
or, because your wrapper already checks for it and makes sure data will not be undefined or null, data!.dashboard_title
.