squiggle/my-react-app/src/FetchedDogPictures/FetchedDogPictures.re
2020-02-05 21:09:27 +00:00

71 lines
2.2 KiB
ReasonML

[@bs.val] external fetch: string => Js.Promise.t('a) = "fetch";
type state =
| LoadingDogs
| ErrorFetchingDogs
| LoadedDogs(array(string));
[@react.component]
let make = () => {
let (state, setState) = React.useState(() => LoadingDogs);
// Notice that instead of `useEffect`, we have `useEffect0`. See
// reasonml.github.io/reason-react/docs/en/components#hooks for more info
React.useEffect0(() => {
Js.Promise.(
fetch("https://dog.ceo/api/breeds/image/random/3")
|> then_(response => response##json())
|> then_(jsonResponse => {
setState(_previousState => LoadedDogs(jsonResponse##message));
Js.Promise.resolve();
})
|> catch(_err => {
setState(_previousState => ErrorFetchingDogs);
Js.Promise.resolve();
})
|> ignore
);
// Returning None, instead of Some(() => ...), means we don't have any
// cleanup to do before unmounting. That's not 100% true. We should
// technically cancel the promise. Unofortunately, there's currently no
// way to cancel a promise. Promises in general should be way less used
// for React components; but since folks do use them, we provide such an
// example here. In reality, this fetch should just be a plain callback,
// with a cancellation API
None;
});
<div
style={ReactDOMRe.Style.make(
~height="120px",
~display="flex",
~alignItems="center",
~justifyContent="center",
(),
)}>
{switch (state) {
| ErrorFetchingDogs => React.string("An error occurred!")
| LoadingDogs => React.string("Loading...")
| LoadedDogs(dogs) =>
dogs
->Belt.Array.mapWithIndex((i, dog) => {
let imageStyle =
ReactDOMRe.Style.make(
~height="120px",
~width="100%",
~marginRight=i === Js.Array.length(dogs) - 1 ? "0px" : "8px",
~borderRadius="8px",
~boxShadow="0px 4px 16px rgb(200, 200, 200)",
~backgroundSize="cover",
~backgroundImage={j|url($dog)|j},
~backgroundPosition="center",
(),
);
<div key=dog style=imageStyle />;
})
->React.array
}}
</div>;
};