Last active
December 8, 2020 20:54
-
-
Save nwellis/916e6896014e1268c9eba8950f1581e6 to your computer and use it in GitHub Desktop.
Resource wrappers in Kotlin and Typescript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed class Resource<T> { | |
object Loading: Resource<Nothing>() | |
data class Success<T>(val data: T): Resource<T>() | |
data class Error(val error: AppError): Resource<Nothing>() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type Resource<T> = ResourceLoading | ResourceSuccess<T> | ResourceError | |
export class ResourceLoading { } | |
export class ResourceSuccess<T> { | |
constructor(readonly data: T) { } | |
} | |
export class ResourceError { | |
constructor(readonly error: AppError) { } | |
} | |
/** | |
* When using the state patter `type State = Readonly<typeof initialState>` with React, a resource should be | |
* of type `Resource`, not the initial state given. Use this to instantiate the `initialState`. | |
* | |
* @param initial Optional state to begin with, if none is provided this defaults to loading | |
*/ | |
export function initialResource<T>(initial?: Resource<T>): Resource<T> { | |
return initial || new ResourceLoading() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type TParams = { | |
gistId: string | |
} | |
type Props = RouteComponentProps<TParams> | |
const initialState = { | |
gist: initialResource<Gist>() | |
} | |
type State = Readonly<typeof initialState> | |
class GistDetail extends React.Component<Props, State> { | |
readonly state: State = initialState | |
componentDidUpdate(prevProps: Props, prevState: State) { | |
const currentId = prevProps.match.params.gistId | |
const nextId = this.props.match.params.gistId | |
if (nextId !== currentId) { | |
this.setState({ | |
gist: new ResourceLoading() | |
}) | |
this.fetchGist(nextId) | |
} | |
} | |
render() { | |
const { gist } = this.state | |
if (gist instanceof ResourceLoading) { | |
return ( | |
<Segment> | |
<Loader active inline='centered' /> | |
</Segment> | |
) | |
} else if (gist instanceof ResourceSuccess) { | |
return ( | |
<Container> | |
<code> | |
{gist.data.url} | |
</code> | |
</Container> | |
) | |
} else { | |
return ( | |
<Container> | |
<h1>{gist.error.message}</h1> | |
</Container> | |
) | |
} | |
} | |
private fetchGist(gistId: string) { | |
console.log(`fetching ${gistId}`) | |
fetch(`https://api.github.com/gists/${gistId}`) | |
.then(res => res.json()) | |
.then(gist => { this.setState({ gist: new ResourceSuccess(gist) }) }) | |
} | |
} | |
export default GistDetail; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I would probably make the following changes: