Skip to content

Instantly share code, notes, and snippets.

@itsMapleLeaf
Last active March 26, 2018 23:01
Show Gist options
  • Save itsMapleLeaf/bb4a00c9edeb39f9430d5ef13c843d7d to your computer and use it in GitHub Desktop.
Save itsMapleLeaf/bb4a00c9edeb39f9430d5ef13c843d7d to your computer and use it in GitHub Desktop.
// *Model represents any piece of data
class TrackModel {
constructor(public data) {
// validate data?
}
}
// *ViewModel represents view state
class TrackListViewModel {
tracks = observable.array<TrackModel>() // rendered by UI
@observable fetching = false
@observable error?: any
@action
clearTracks() {
this.tracks.clear()
}
@action
addTracks(tracks: TrackModel[]) {
this.tracks.push(...tracks)
}
@action
setError(error: any) {
this.error = error
}
@action
setFetching(fetching: boolean) {
this.fetching = fetching
}
fetchTracks() {
if (this.fetching) {
return
}
this.setFetching(true)
this.setError(undefined)
axios
.get("/tracks")
.then(res => {
const models = res.data.tracks.map(data => new TrackModel(data))
this.addTracks(models)
})
.catch(error => {
this.setError(error)
})
.finally(() => {
this.setFetching(false)
})
}
}
class TrackList extends React.Component {
viewModel = new TrackListViewModel()
componentDidMount() {
// clear and fetch tracks on mount
this.viewModel.clearTracks()
this.viewModel.fetchTracks()
}
handleScroll = event => {
const el = event.currentTarget
if (scrolledToBottom(el)) {
this.viewModel.fetchTracks()
}
}
render() {
return (
<div onScroll={this.handleScroll}>
{/* render tracks (if any) */}
{this.viewModel.tracks.map(track => <TrackListItem key={track.data.id} track={track} />)}
{/* display spinner if we're currently fetching more */}
{this.viewModel.fetching && <LoadingSpinner />}
{/* display error at the bottom of the list if something fucked up */}
{this.viewModel.error && <ErrorMessage error={this.viewModel.error} />}
</div>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment