February 5th, 2022
HOC
img

I saw many times functions like withIntl withRouter these injected some variables that can be used inside the components. These are called the HOCs. Higher Order Component is a Design pattern. Lets take a look at it with an example.

A sample Without HOC

Copy 📋
import React, {useState} from "react";

const ComponentWithSpinner = () => {
  const [isDataFetching, setIsDataFetching] = useState(true);
  const [isDataFetched, setIsDataFetched] = useState(true);
  const [data, setData] = useState({});

  useEffect( () => {
    setIsDataFetching(true);
    fetchData().then( fetchedData => {
      setData(fetchedData);
      setIsDataFetched(true);
      setIsDataFetching(false);
    })
  }, []);

  if(!isDataFetched) {
    return <Spinner text = "Loading your Page...">;
  }

  return (
      <Page data={data}/>
  );
};

export default ComponentWithSpinner;

Whats the Problem here?

This spinning logic should be applied to multiple pages. In that case all the code related to showing Spinner when page is not ready will be duplicated. We can maybe make it Generalized for all pages somehow so we dont need to write it again and again.

Now with HOC

Copy 📋
import React, { useState } from "react";

const withSpinner = (WrappedComponent) => {
  const SpinnerOrComponent = ({ isLoading, ...otherProps }) => {
    if(isLoading) {
      return <Spinner text = "Loading your Page...">;
    }
    return <WrappedComponent {...otherProps} />;
  };
  return SpinnerOrComponent;
};

export default withSpinner;
Copy 📋
import React, { useState } from "react";
import withSpinner from "./withSpinner";

const Page = ({data}) => {
  ...
};

export default withSpinner(Page);
Copy 📋
import React, { useState } from "react";

const MainPage = () => {
  const [isDataFetching, setIsDataFetching] = useState(true);
  const [isDataFetched, setIsDataFetched] = useState(true);
  const [data, setData] = useState({});

  useEffect(() => {
    setIsDataFetching(true);
    fetchData().then((fetchedData) => {
      setData(fetchedData);
      setIsDataFetched(true);
      setIsDataFetching(false);
    });
  }, []);

  return <Page isLoading={isDataFetching || !isDataFetched} data={data} />;
};

export default withSpinner;