Skip to content

Instantly share code, notes, and snippets.

@SakuOtonashi
Created November 16, 2021 11:05
Show Gist options
  • Save SakuOtonashi/c98aa31d2b5fdc82ba0bcdb1eb8e07cd to your computer and use it in GitHub Desktop.
Save SakuOtonashi/c98aa31d2b5fdc82ba0bcdb1eb8e07cd to your computer and use it in GitHub Desktop.
import { getUnreadMessageCount } from '../services/message'
export class State {
message = { unreadCount: 0 }
async getUnreadMessageCount() {
this.message.unreadCount = await getUnreadMessageCount()
}
}
import stateStore from '../../stores/state'
Page({
data: {
// 也可以只指定部分属性同步时也只会同步这一部分
stateData: stateStore.data,
},
onLoad() {
// @ts-ignore
this._ssViewId = stateStore.connectAndUpdate('stateData', this)
},
onUnload() {
// @ts-ignore
stateStore.disconnect(this._ssViewId)
},
getUnreadCount() {
stateStore.getUnreadMessageCount()
},
})
import { State } from '../models/state'
import { WeStore } from './utils'
class StateStore extends WeStore<Pick<State, 'message'>> {
state: State
constructor() {
super()
this.state = new State()
this._computeData()
}
private _computeData() {
this.data = {
message: this.state.message,
}
}
async getUnreadMessageCount() {
await this.state.getUnreadMessageCount()
this._computeData()
this.update()
}
clearAllInfo() {
this.state.message = { unreadCount: 0 }
this._computeData()
this.update()
}
}
// 可以和多个页面组件联结实现自动绑定共享数据
const stateStore = new StateStore()
export default stateStore
// 参考 [westore](https://github.com/Tencent/westore)
// 只做浅层比较
export function diffData<V extends Record<string, any>, K extends Partial<V>>(
current: K,
previous: V
) {
const patch: Partial<V> & Record<string, any> = {}
;(Object.keys(previous) as (keyof V)[]).forEach((key) => {
const curVal = current[key]
const preVal = previous[key]
if (curVal !== undefined && curVal !== preVal) {
if (Array.isArray(curVal) && Array.isArray(preVal)) {
if (
curVal.length >= preVal.length &&
curVal.length <= preVal.length * 1.25
) {
// 浅层数据里的数组类型仅在增加和修改少量成员的情况下会拆出来单独更新
const changes: number[] = []
;(curVal as any[]).forEach((item, index) => {
if (preVal[index] !== item) {
changes.push(index)
}
})
if (changes.length * 5 <= curVal.length) {
changes.forEach((i) => {
// @ts-ignore
patch[key + '[' + i + ']'] = curVal[i]
})
return
}
}
}
patch[key] = curVal
}
})
return patch
}
export class WeStore<V extends Record<string, any>> {
private _weStoreViews: Record<string, QuasiView<Partial<V>>> = {}
private _weStoreViewId: number = 0
public data = {} as V
connect<T extends string>(
prop: T,
view: PageOrComponent<T, Partial<V>>,
viewId?: string | number
) {
const quasiView = newQuasiView(prop, view)
const viewId2 = viewId || this._weStoreViewId++
this._weStoreViews[viewId2] = quasiView
return viewId2
}
disconnect(viewId: string) {
delete this._weStoreViews[viewId]
}
connectAndUpdate<T extends string>(
prop: T,
view: PageOrComponent<T, Partial<V>>,
viewId?: string | number
) {
const viewId2 = this.connect(prop, view, viewId)
this.update(viewId2)
return viewId2
}
update(viewId?: string | number) {
if (viewId) {
updateView(this._weStoreViews[viewId], this.data)
} else {
Object.values(this._weStoreViews).forEach((view) => {
updateView(view, this.data)
})
}
}
}
export interface PageOrComponent<
T extends string,
V extends Record<string, any>
> {
data: { [K in T]: V } & Record<string, any>
setData: (
data: { [K in T]: any } & Record<string, any>,
callback?: () => void
) => void
}
// 视图简化的抽象接口
interface QuasiView<V extends Record<string, any>> {
getData: () => V
setData: (
data: Partial<V> & Record<string, any>,
callback?: () => void
) => void
}
function newQuasiView<T extends string, V extends Record<string, any>>(
prop: T,
view: PageOrComponent<T, V>
) {
const quasiView: QuasiView<V> = {
getData() {
return view.data[prop]
},
setData(data, callback) {
const subData: any = {}
Object.keys(data).forEach((key) => {
subData[prop + '.' + key] = data[key]
})
view.setData(subData, callback)
},
}
return quasiView
}
function updateView<V extends Record<string, any>>(
quasiView: QuasiView<V>,
data: Partial<V> & Record<string, any>,
callback?: () => void
) {
const patch = diffData(data, quasiView.getData())
quasiView.setData(patch, callback)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment