Skip to content

Instantly share code, notes, and snippets.

@flpsoares
Last active September 13, 2021 12:05
Show Gist options
  • Save flpsoares/9b5db12d1eb1cde5157952239edd041e to your computer and use it in GitHub Desktop.
Save flpsoares/9b5db12d1eb1cde5157952239edd041e to your computer and use it in GitHub Desktop.
Collection
declare namespace App {
export interface Model {
id: number
created_at: Date
updated_at: Date
}
}
import { TypedEmitter } from 'tiny-typed-emitter'
export class Collection<T = any> extends TypedEmitter<{
forceUpdate: () => void
}> {
private collection: T[] = []
private primaryKey: string = 'id'
public addMany(items: T[]) {
for (const item of items) {
this.set(item)
}
}
public set(item: Partial<T>) {
if (this.exists(this.getPrimaryKey(item))) {
this.update(item)
} else {
this.add(item)
}
this.forceUpdate()
}
public all() {
return this.collection
}
public add(item: Partial<T>) {
// @ts-ignore
this.collection.push(item)
return item
}
public update(item: Partial<T>) {
const findedItem = this.findByPrimaryKey(this.getPrimaryKey(item))
for (const keyItem in item) {
findedItem[keyItem] = item[keyItem]
}
return findedItem
}
public delete(primaryKey: any) {
this.collection = this.collection.filter((item) => {
return this.getPrimaryKey(item) !== primaryKey
})
this.forceUpdate()
}
public forceUpdate() {
this.emit('forceUpdate')
}
public exists(primaryKey: any) {
return !!this.findByPrimaryKey(primaryKey)
}
public findByPrimaryKey(primaryKey: any) {
return this.collection.find((item) => {
return this.getPrimaryKey(item) === primaryKey
})
}
private getPrimaryKey(item: Partial<T>) {
return item[this.primaryKey]
}
}
import { useEffect, useMemo, useState } from 'react'
import { Collection } from '../services/helpers/Collection'
import useDebounce from './helpers/useDebounce'
export function useCollection<T>(collection: Collection<T>) {
const [lastUpdate, setLastUpdate] = useState<number>(0)
const lastUpdateDebounce = useDebounce(lastUpdate, 500)
const items = useMemo(() => {
return collection.all()
}, [lastUpdateDebounce])
const onForceUpdate = () => {
setLastUpdate(Date.now())
}
useEffect(() => {
collection.on('forceUpdate', onForceUpdate)
return () => {
collection.off('forceUpdate', onForceUpdate)
}
}, [])
return { items }
}
import { useEffect, useState } from 'react'
function useDebounce<T>(value: T, delay?: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay || 500)
return () => {
clearTimeout(timer)
}
}, [value, delay])
return debouncedValue
}
export default useDebounce
declare namespace App {
export interface User extends App.Model {
username: string
password: string
email?: string
}
}
import { api } from '../api'
import UsersCollection from '../collections/UsersCollection'
class UserApi {
public async create({ username, password, email }: Partial<App.User>) {
return api.post('user', {
username,
password,
email
})
}
public async list() {
return api
.get<App.User[]>('users')
.then((res) => res.data)
.then((users) => {
UsersCollection.addMany(users)
return users
})
}
public async delete(user: App.User) {
return api.delete(`user/${user.id}`).then(() => {
UsersCollection.delete(user.id)
})
}
}
export default new UserApi()
import { Collection } from '../helpers/Collection'
class UsersCollection extends Collection<App.User> {}
export default new UsersCollection()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment