На моем проекте я сделал такой велосипед, не доделан случай, когда не требуется заменять собой весь компонент, стили измените под себя:
import PropTypes from 'prop-types';
import csx from 'classnames';
export const MessageContainer = ({ theme, children }) => (
<div className={csx('root', theme)}>
{/* language=SCSS */}
<style jsx>{`
.root {
font-weight: 500;
display: flex;
flex: 1;
align-items: center;
justify-content: center;
font-size: 14px;
padding: 24px;
}
.error {
color: var(--error-color);
}
.loading {
color: var(--accent-color);
}
.empty {
color: #bbbbbb;
}
`}</style>
{children}
</div>
);
MessageContainer.propTypes = {
theme: PropTypes.oneOf(['loading', 'empty', 'error']).isRequired,
children: PropTypes.node.isRequired,
};
export default function withQueryStatus({ emptyText = 'Nothing found', replaceComponent = true, resultPath }) {
if (!replaceComponent) {
throw new Error('Not implemented');
}
return (ComposedComponent) => {
const WithQueryStatus = (props) => {
const data = props.data;
if (!data) {
return null;
}
if (data.error) {
return <MessageContainer theme='error'>{data.error.message}</MessageContainer>;
}
if (data.loading) {
return <MessageContainer theme='loading'>Loading...</MessageContainer>;
}
if (!data[resultPath].length) {
return <MessageContainer theme='empty'>{emptyText}</MessageContainer>;
}
return <ComposedComponent {...props} />;
};
WithQueryStatus.propTypes = {
data: PropTypes.shape({
[resultPath]: PropTypes.array,
loading: PropTypes.bool,
error: PropTypes.object,
}),
};
WithQueryStatus.defaultProps = {
data: null,
};
return WithQueryStatus;
};
}
// у вас будет
export default withQueryStatus({ emptyText: 'No todos found', resultPath: 'todos' })(Todos),