Skip to content

Commit

Permalink
feat: add provider & inject
Browse files Browse the repository at this point in the history
  • Loading branch information
cicec committed May 2, 2020
1 parent 95d9f7f commit c2ffb74
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 96 deletions.
2 changes: 2 additions & 0 deletions src/@types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type ComponentOptions = WechatMiniprogram.Component.Options<AnyObject, AnyObject, AnyObject>
type PageOptions = WechatMiniprogram.Page.Options<AnyObject, AnyObject>
69 changes: 69 additions & 0 deletions src/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { autorun, IReactionDisposer } from 'mobx'
import { is } from './utils'
import diff from './diff'

const create = {
page: (stores: AnyObject, mapper: Function, options: PageOptions) => {
let dispose: IReactionDisposer

const { data = {}, onLoad, onUnload } = options

return Page({
...options,
data: { ...data, ...mapper(stores) },

onLoad(query) {
dispose = autorun(() => {
if (this.data) {
const diffs: AnyObject = diff({ ...this.data, ...mapper(stores) }, this.data)

for (const key in diffs) {
if (key) this.setData({ [key]: diffs[key] })
}
}
})

if (is.fun(onLoad)) onLoad.call(this, query)
},

onUnload() {
if (dispose) dispose()

if (is.fun(onUnload)) onUnload.call(this)
},
})
},

component(stores: AnyObject, mapper: Function, options: ComponentOptions) {
let dispose: IReactionDisposer

const { data = {}, attached, detached } = options

return Component({
...options,
data: { ...data, ...mapper(stores) },

attached() {
dispose = autorun(() => {
if (this.data) {
const diffs: AnyObject = diff({ ...this.data, ...mapper(stores) }, this.data)

for (const key in diffs) {
if (key) this.setData({ [key]: diffs[key] })
}
}
})

if (is.fun(attached)) attached.call(this)
},

detached() {
if (dispose) dispose()

if (is.fun(detached)) detached.call(this)
},
})
},
}

export default create
6 changes: 4 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import provider from './provider'
import inject from './inject'
import observer from './observer'

export default observer
export { observer }
export default { provider, inject, observer }
export { provider, inject, observer }
28 changes: 28 additions & 0 deletions src/inject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import create from './create'
import { toData } from './utils'

const mapStores = (names: string[]) => (source: AnyObject) => {
const target: AnyObject = {}

names.forEach((key) => {
if (source && source[key]) {
target[key] = toData(source[key])
}
})

return target
}

const inject = {
page: (...storeNames: string[]) => (
createOptions: (stores: AnyObject) => PageOptions
) =>
create.page(getApp().stores, mapStores(storeNames), createOptions(getApp().stores)),

component: (...storeNames: string[]) => (
createOptions: (stores: AnyObject) => ComponentOptions
) =>
create.component(getApp().stores, mapStores(storeNames), createOptions(getApp().stores)),
}

export default inject
100 changes: 6 additions & 94 deletions src/observer.ts
Original file line number Diff line number Diff line change
@@ -1,100 +1,12 @@
import { autorun, toJS, isObservable, IReactionDisposer } from 'mobx'
import diff from './diff'

type ComponentOptions = WechatMiniprogram.Component.Options<AnyObject, AnyObject, AnyObject>
type PageOptions = WechatMiniprogram.Page.Options<AnyObject, AnyObject>

const is = {
fun: (a: unknown): a is Function => typeof a === 'function',
obj: (a: unknown): a is AnyObject => Object.prototype.toString.call(a) === '[object Object]',
}

const mapProps = (source: AnyObject) => (operation: Function) => {
const target: AnyObject = {}

Object.getOwnPropertyNames(source)
.filter((key) => !is.fun(source[key]))
.forEach((key) => {
target[key] = operation(source[key])
})

return target
}

const toData = (source: any) => {
if (is.obj(source)) {
return mapProps(source)(isObservable(source) ? toJS : toData)
}

return source
}
import create from './create'
import { toData } from './utils'

const observer = {
page(store: AnyObject) {
return (options: PageOptions) => {
let dispose: IReactionDisposer

const { data = {}, onLoad, onUnload } = options

return Page({
...options,
data: { ...data, ...toData(store) },

onLoad(query) {
dispose = autorun(() => {
if (this.data) {
const diffs: AnyObject = diff({ ...this.data, ...toData(store) }, this.data)

for (const key in diffs) {
if (key) this.setData({ [key]: diffs[key] })
}
}
})

if (is.fun(onLoad)) onLoad.call(this, query)
},

onUnload() {
if (dispose) dispose()

if (is.fun(onUnload)) onUnload.call(this)
},
})
}
},

component(store: AnyObject) {
return (options: ComponentOptions) => {
let dispose: IReactionDisposer

const { data = {}, attached, detached } = options

return Component({
...options,
data: { ...data, ...toData(store) },

attached() {
dispose = autorun(() => {
if (this.data) {
const diffs: AnyObject = diff({ ...this.data, ...toData(store) }, this.data)

for (const key in diffs) {
if (key) this.setData({ [key]: diffs[key] })
}
}
})

if (is.fun(attached)) attached.call(this)
},

detached() {
if (dispose) dispose()
page: (stores: AnyObject) => (options: PageOptions) =>
create.page(stores, toData, options),

if (is.fun(detached)) detached.call(this)
},
})
}
},
component: (stores: AnyObject) => (options: ComponentOptions) =>
create.component(stores, toData, options),
}

export default observer
6 changes: 6 additions & 0 deletions src/provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type AppOptions = WechatMiniprogram.App.Options<AnyObject>

const provider = <T extends AnyObject>(stores: T) => (options: AppOptions) =>
App({ ...options, stores })

export default provider
27 changes: 27 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { isObservable, toJS } from 'mobx'

export const is = {
fun: (a: unknown): a is Function => typeof a === 'function',
obj: (a: unknown): a is AnyObject =>
Object.prototype.toString.call(a) === '[object Object]',
}

const mapProps = (source: AnyObject) => (operation: Function) => {
const target: AnyObject = {}

Object.getOwnPropertyNames(source)
.filter((key) => !is.fun(source[key]))
.forEach((key) => {
target[key] = operation(source[key])
})

return target
}

export const toData = (source: any) => {
if (is.obj(source)) {
return mapProps(source)(isObservable(source) ? toJS : toData)
}

return source
}

0 comments on commit c2ffb74

Please sign in to comment.