UNPKG

4.04 kBJavaScriptView Raw
1import { enqueueRender } from './render-queue'
2import { updateComponent } from './lifecycle'
3import { isFunction, genCompPrefix } from './util'
4import {
5 internal_safe_get as safeGet,
6 internal_force_update as forceUpdateCallback
7} from '@tarojs/taro'
8import { cacheDataSet, cacheDataGet } from './data-cache'
9// #组件state对应小程序组件data
10// #私有的__componentProps更新用于触发子组件中对应obsever,生命周期componentWillReceiveProps,componentShouldUpdate在这里处理
11// #父组件传过来的props放到data.__props中供模板使用,这么做的目的是模拟receiveProps生命周期
12// 执行顺序:组件setState -> 组件_createData() -> 对应的小程序组件setData(组件更新)-> 子组件的__componentProps.observer执行
13// -> 触发子组件componentWillReceiveProps,更新子组件props,componentShouldUpdate -> 子组件_createData -> 子组件setData
14
15const PRELOAD_DATA_KEY = 'preload'
16
17class BaseComponent {
18 // _createData的时候生成,小程序中通过data.__createData访问
19 __computed = {}
20 // this.props,小程序中通过data.__props访问
21 __props = {}
22 __isReady = false
23 // 会在componentDidMount后置为true
24 __mounted = false
25 nextProps = {}
26 _dirty = true
27 _disable = true
28 _isForceUpdate = false
29 _pendingStates = []
30 _pendingCallbacks = []
31 $componentType = ''
32 $router = {
33 params: {},
34 path: ''
35 }
36
37 _afterScheduleEffect = false
38 _disableEffect = false
39 hooks = []
40 effects = []
41 layoutEffects = []
42
43 constructor (props = {}, isPage) {
44 this.state = {}
45 this.props = props
46 this.$componentType = isPage ? 'PAGE' : 'COMPONENT'
47 this.$prefix = genCompPrefix()
48 this.isTaroComponent = this.$componentType && this.$router && this._pendingStates
49 }
50 _constructor (props) {
51 this.props = props || {}
52 }
53 _init (scope) {
54 this.$scope = scope
55 }
56 setState (state, callback) {
57 if (state) {
58 (this._pendingStates = this._pendingStates || []).push(state)
59 }
60 if (isFunction(callback)) {
61 (this._pendingCallbacks = this._pendingCallbacks || []).push(callback)
62 }
63 if (!this._disable) {
64 enqueueRender(this, callback === forceUpdateCallback)
65 }
66 }
67
68 getState () {
69 const { _pendingStates, state, props } = this
70 const stateClone = Object.assign({}, state)
71 delete stateClone.__data
72 if (!_pendingStates.length) {
73 return stateClone
74 }
75 const queue = _pendingStates.concat()
76 this._pendingStates.length = 0
77 queue.forEach((nextState) => {
78 if (isFunction(nextState)) {
79 nextState = nextState.call(this, stateClone, props)
80 }
81 Object.assign(stateClone, nextState)
82 })
83 return stateClone
84 }
85
86 forceUpdate (callback) {
87 if (isFunction(callback)) {
88 (this._pendingCallbacks = this._pendingCallbacks || []).push(callback)
89 }
90 this._isForceUpdate = true
91 updateComponent(this)
92 }
93
94 $preload (key, value) {
95 const preloadData = cacheDataGet(PRELOAD_DATA_KEY) || {}
96 if (typeof key === 'object') {
97 for (const k in key) {
98 preloadData[k] = key[k]
99 }
100 } else {
101 preloadData[key] = value
102 }
103 cacheDataSet(PRELOAD_DATA_KEY, preloadData)
104 }
105
106 // 会被匿名函数调用
107 __triggerPropsFn (key, args) {
108 const keyChain = key.split('.')
109 const reduxFnPrefix = '__event_'
110 const reduxFnName = reduxFnPrefix + keyChain.shift()
111 // redux标识过的方法,直接调用
112 if (reduxFnName in this) {
113 const scope = args.shift()
114 let fn
115 if (keyChain.length > 0) {
116 fn = safeGet(this[reduxFnName], keyChain.join('.'))
117 } else {
118 fn = this[reduxFnName]
119 }
120 fn.apply(scope, args)
121 } else {
122 // 普通的
123 const keyLower = key.toLocaleLowerCase()
124 const detail = {
125 __isCustomEvt: true,
126 __arguments: args
127 }
128 if (args.length > 0) {
129 detail.value = args.slice(1)
130 }
131 this.$scope.triggerEvent(keyLower, detail)
132 }
133 }
134}
135
136export default BaseComponent