A ReasonReact useFetch hook. It:
- wraps bs-fetch
- is composable
- uses a
result
type - makes impossible state irrepresentable
- lets you use a JSON decoding library of your choice
- lets you compose fetch errors and decoding error via polymorphic variants
- uses a
It seems workable, especially for getting data, but expect some breaking changes before v1.0.
[@react.component]
let make = () => {
UseFetch.(
// fetch the data
useFetch(
"https://api.github.com/search/repositories?q=language:reason&sort=stars&order=desc",
)
// use whichever decoding library you like
->mapOk(r => GhRepo.t_decode(r)->Decode.mapDecodingError)
->(
// below, no distinction is made between fetching and refetching,
// but you're free to make other UX choices
fun
| Fetching => ReasonReact.string("Loading...")
| Refetching(Ok(({items}: GhRepo.t)))
| Complete(Ok(({items}: GhRepo.t))) =>
<ul>
{Belt.Array.map(items, ({fullName, htmlUrl}: GhRepo.repo) =>
<li key=fullName>
<a href=htmlUrl> {ReasonReact.string(fullName)} </a>
</li>
)
->React.array}
</ul>
| Refetching(Error(`FetchError(_)))
| Complete(Error(`FetchError(_))) =>
<h2> {ReasonReact.string("Fetch error!")} </h2>
| Refetching(Error(`DecodeError((err: Decco.decodeError))))
| Complete(Error(`DecodeError((err: Decco.decodeError)))) =>
<h2> {ReasonReact.string("Decode error!")} </h2>
);
};
(See the full example in /examples
.)
Or, if you prefer the style prevalent in JS-land,
let (loading, data, error) = UseFetch.(
useFetch(
"https://api.github.com/search/repositories?q=language:reason&sort=stars&order=desc",
)
->mapOk(r => GhRepo.t_decode(r)->Decode.mapDecodingError)
->toLoadingDataAndError
);
// ...
See UseFetch.rei
.
- Add request/init parameters
- Support submitting
-
toLoadingAndResult
helper - use
AbortController
(bs-fetch
has a stale PR for same) - tests (will probably require bindings for something like jest-fetch-mock)
- Generate API docs (the comments in the
.rei
should already be odoc-compatible. - React Suspense compatibility?