Home > Software engineering >  Passing runtime data from a component to a HoC?
Passing runtime data from a component to a HoC?

Time:11-13

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.

  • Related