Skip to content

Instantly share code, notes, and snippets.

@busypeoples
Created March 7, 2020 23:04
Show Gist options
  • Save busypeoples/6e88899c81825964ac614cc2e71fc2f5 to your computer and use it in GitHub Desktop.
Save busypeoples/6e88899c81825964ac614cc2e71fc2f5 to your computer and use it in GitHub Desktop.
Explicit State Views
import React from "react";
type NoData = {
_type: "NO_DATA";
};
type Data<T> = {
_type: "DATA";
data: T;
};
type Loading<T> = {
_type: "LOADING";
data?: T;
};
type Error<E> = {
_type: "ERROR";
msg: E;
};
type AppState<T, E> = NoData | Data<T> | Loading<T> | Error<E>;
type R<T> = React.ComponentType<T>;
type View<T, E, P> = {
NoData: R<P>;
Data: R<{ data: T } & P>;
Loading: R<P>;
Error: R<{ msg: E } & P>;
};
type ExplicitViewsProps<T, E, P = {}> = {
views: View<T, E, Omit<P, "views" | "state">>;
state: AppState<T, E>;
} & P;
const ExplicitViews = <T, E, P>({
state,
views,
...props
}: ExplicitViewsProps<T, E, P>) => {
const { NoData, Data, Loading, Error } = views;
switch (state._type) {
case "NO_DATA":
return <NoData {...props} />;
case "DATA":
return <Data data={state.data} {...props} />;
case "LOADING":
return <Loading data={state.data} {...props} />;
case "ERROR":
return <Error msg={state.msg} {...props} />;
}
};
// Example
type AppProps = { title: string };
const View = ({ title }: AppProps) => {
return (
<ExplicitViews<string, string, AppProps>
title={title}
state={{ _type: "NO_DATA" }}
views={{
NoData: ({ title }) => <div>{title}: We have no data.</div>,
Data: ({ data }) => {
return <div>We have some data: {data}</div>;
},
Loading: () => <div>Loading...</div>,
Error: ({ msg }) => <div>We have an error: {msg}</div>
}}
/>
);
};
export default View;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment