Skip to content

Instantly share code, notes, and snippets.

@kodiyak
Created June 4, 2021 12:43
Show Gist options
  • Save kodiyak/c3100f15b2e88cb0664e24524d0a830c to your computer and use it in GitHub Desktop.
Save kodiyak/c3100f15b2e88cb0664e24524d0a830c to your computer and use it in GitHub Desktop.
Loaders

Loaders

Useful code to handle loaders on application

Usage:

// api
Loaders.start(`Loader/Name`)

api.request('...').finally(() => {
  Loaders.finish(`Loader/Name`)
})

// component (React)
const { isLoading, isLoadingNamespace } = useLoaders(`Loader/Name`)

const Component = () => {
  return (
    <Button 
      isLoading={isLoading} 
      onClick={() => {
        // api call
      }}
    ></Button>
  )
}
import { TypedEmitter } from 'tiny-typed-emitter'
type TypeLoader = {
[key: string]: number
}
class Loaders extends TypedEmitter<{
start: (name: string) => void
finish: (name: string) => void
forceUpdate: () => void
}> {
private loaders: TypeLoader = {}
public start(name: string) {
if (this.isLoading(name)) {
this.increment(name)
} else {
this.loaders[name] = 1
}
this.emit('start', name)
this.emit('forceUpdate')
}
public finish(name: string) {
this.decrement(name)
this.emit('finish', name)
this.emit('forceUpdate')
}
public isLoading(name: string) {
for (const loaderName in this.loaders) {
const loader = this.loaders[loaderName]
if (loaderName === name) {
return loader > 0
}
}
return false
}
public isLoadingNamespace(name: '*' | string) {
for (const loaderName in this.loaders) {
const loader = this.loaders[loaderName]
if ((loaderName.startsWith(name) || name === '*') && loader > 0) {
return true
}
}
return false
}
private increment(name: string) {
this.loaders[name]++
}
private decrement(name: string) {
this.loaders[name]--
}
}
export default new Loaders()
import { useMemo, useState, useEffect } from 'react'
import Loaders from '../services/helpers/Loaders'
export function useLoaders(name: '*' | string) {
const [lastUpdate, setLastUpdate] = useState(0)
const onForceUpdate = () => {
setLastUpdate(() => Date.now())
}
const isLoading = useMemo(() => {
return Loaders.isLoading(name)
}, [name, lastUpdate])
const isLoadingNamespace = useMemo(() => {
return Loaders.isLoadingNamespace(name)
}, [name, lastUpdate])
useEffect(() => {
Loaders.on('forceUpdate', onForceUpdate)
return () => {
Loaders.off('forceUpdate', onForceUpdate)
}
}, [])
return {
isLoading,
isLoadingNamespace
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment