The grass is rarely greener, but it's always different

Render a loader contidionally in React with a High Order Component

There are multiple places where we load data asynchronously in TheGoodPsy's web application, so we use the ReactLoading package to show a spinner while the data is being downloaded and processed in the frontend.

There is a common block of code that gets repeated:

{loading ? (
   <ReactLoading
      className="chat-loader"
      type="spin"
      color={COLOR} />
   ) :
   <>whatever content here</>
}

Sometimes the loader needs to be wrapped in a different html skeleton, being the perfect place to use a render prop. I took a bit of time to myself to write a simple HOC that would show a spinner based on loading property, and can wrap the loader using a custom template from a render prop.

const WithLoader = ({
   loading,
   loadingTemplate,
   style,
   height,
   width,
   color,
   children
}) => {
   const internalLoadingTemplate = () => {
      const loader = (
         <ReactLoading
            { ...style }
            height={height || 16}
            width={width || 16}
            type="spin"
            color={color || CUSTOM_COLOR} />
        );
        return loadingTemplate ?
           loadingTemplate(loader) : 
           <>{ loader }</>;
   }
   return (
      loading ? 
         internalLoadingTemplate() :
         <> {children} </>
   );
};

export default WithLoader;

So in order to use it without any defaults (other than loading) is for example:

<WithLoader loading={true}>
   <span onClick={joinCall}>
      join call
   </span>
</WithLoader>

And if we want to wrap the loader in a custom format we use a render prop. Important to note we need to explicitly render the loader within it.

<WithLoader
   loading={true}
   loadingTemplate={(loader) => {
      return (
         <div classNames="custom-loader">
            <span>
               { loader} 
            </span>
         </div>
      )
   }}>
   <span 
      className="join-call-link"
      onClick={(e)=> joinCall(e, roomSid, isAudioOnly)}>
        { t('JOIN_CALL_JOIN') }
    </span>
</WithLoader>

#javascript #learning #web