Slaying a UI Antipattern with Flow

The problem

{ loading: true, items: [] }
type Model = {
things: ?Array<Thing>
};
const SomeView = ({ things }: Model) => {
return <div>
{ things.map(thing => { ... }) }
</div>
}
{model.things.map(thing => {})}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call of method `map`. Method cannot be called on possibly null value
{model.things.map(thing => {})}
^^^^^^^^^^^^ null
type Maybe<A> = ?A;type Model = {
things: Maybe<Array<Thing>>
};

The solution

  • we haven’t asked yet
  • we’ve asked, but we haven’t got a response yet
  • we got a response, but it was an error
  • we got a response, and it was the data we wanted
type RemoteData<E, D>
= { type: 'NotAsked' }
| { type: 'Loading' }
| { type: 'Failure', error: E }
| { type: 'Success', data: D };
type Model = {
things: RemoteData<HttpError, Array<Thing>>
};
// will raise: property `data`. Property not found in object type
const SomeView = ({ things }: Model) => {
return <div>
{ things.data.map(thing => {}) }
</div>
}
const SomeView = ({ things }: Model) => {
if (things.type === 'NotAsked') {
return <div>Please press the button to load the things</div>
}
else if (things.type === 'Loading') {
return <div>Loading things...</div>
}
else if (things.type === 'Failure') {
return <div>An error has occurred { things.error }</div>
}
return <div>
{ things.data.map(thing => { ... }) }
</div>
}
function fold<R>(
notAsked: () => R,
loading: () => R,
failure: (error: HttpError) => R,
success: (data: Array<Thing>) => R
): (model: Model) => R {
return ({ things }) => {
return things.type === 'NotAsked' ? notAsked() :
things.type === 'Loading' ? loading() :
things.type === 'Failure' ? failure(things.error) :
success(things.data) }
}
const SomeView = fold(
() => <div>Please press the button to load the things</div>,
() => <div>Loading things...</div>,
(error) => <div>An error has occurred { error }</div>,
(data) => <div>{ data.map(thing => {}) }</div>
)

mathematician and rock climber

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
gcanti

gcanti

mathematician and rock climber

More from Medium

Everyone Needs a Map… And Maybe a Filter

React, ViteJS, TypeScript, and Jest

The Plan for React 18…..

Form Validation with Material UI TextField component and React