Render a loader contidionally in React with a High Order Component

There are multiple places where we load data asynchronously in TheGoodPsy, 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 the render prop.

<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>