Separating UI states from API Request Status
function MyComponent() {
const {
isLoading,
error,
hasFetched,
isError,
data,
} = useApi(...)
if (!isLoading && hasFetched && isError) {
return <Error error={error} />
}
if (isLoading) {
return <Spinner />
}
if (hasFetched && !isError) {
return <RealUi />
}
}
function MyComponent() {
const {
isLoading,
error,
hasFetched,
isError,
data,
} = useApi(...)
if (!isLoading && hasFetched && isError) {
return <Error error={error} />
}
if (isLoading) {
return <Spinner />
}
if (hasFetched && !isError) {
return (
<div>
{data.items && data.items.length && <div>{data.items.map(item => item.name)}</div>}
{ /* after some runtime error in prod we add the next line */}
{!data.items || !data.items.length && <div>No results found</div>}
</div>
)
}
the way forward
type ReactLeft<ComponentProps = {
title?: string
reason?: string
}> = { type: UI_STATES, props?: ComponentProps };
const error: ReactLeft<{ title: string }> = {
type: UI_STATES.error,
props: {
title: 'No privileges',
reason: 'You are trying to access "creditCards_db" without read scopes.'
}
}
const loading: ReactLeft = {
type: UI_STATES.loading,
}
const invalid: ReactLeft<WildAssProps> = {
type: UI_STATES.invalid,
props: {
some: 'random',
prop: 'types',
thatYour: 'component',
needs: '!!!',
}
}
import { RandomFactsAboutPotatoes, CuteBrokenPotatoGraphic } from './LeftComponents'
function Aloo() {
const data: either.Either<ReactLeft, Potato[]> = useApi(...)
return (
<div className={layoutWrapper}>
{
pipe(
data,
either.fold(
reactLeftToJSX({
[UI_STATES.loading]: RandomFactsAboutPotatoes,
[UI_STATES.error]: CuteBrokenPotatoGraphic,
}),
(user) => (
<PotatoList />
),
),
)
}
</div>
)
}