UNPKG

3.96 kBJavaScriptView Raw
1import { enqueueRender } from './render-queue'
2import { updateComponent } from './lifecycle'
3import { 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,生命周期componentWillReciveProps,componentShouldUpdate在这里处理
11// #父组件传过来的props放到data.__props中供模板使用,这么做的目的是模拟reciveProps生命周期
12// 执行顺序:组件setState -> 组件_createData() -> 对应的小程序组件setData(组件更新)-> 子组件的__componentProps.observer执行
13// -> 触发子组件componentWillReciveProps,更新子组件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 // hooks
38 _afterScheduleEffect = false
39 _disableEffect = false
40 hooks = []
41 effects = []
42 layoutEffects = []
43
44 constructor (props = {}, isPage) {
45 this.state = {}
46 this.props = {}
47 this.$componentType = isPage ? 'PAGE' : 'COMPONENT'
48 this.$prefix = genCompPrefix()
49 this.isTaroComponent = this.$componentType && this.$router && this._pendingStates
50 }
51 _constructor (props) {
52 this.props = props || {}
53 }
54 _init (scope) {
55 this.$scope = scope
56 }
57 setState (state, callback) {
58 if (state) {
59 (this._pendingStates = this._pendingStates || []).push(state)
60 }
61 if (typeof callback === 'function') {
62 (this._pendingCallbacks = this._pendingCallbacks || []).push(callback)
63 }
64 if (!this._disable) {
65 enqueueRender(this, callback === forceUpdateCallback)
66 }
67 }
68
69 getState () {
70 const { _pendingStates, state, props } = this
71 const stateClone = Object.assign({}, state)
72 delete stateClone.__data
73 if (!_pendingStates.length) {
74 return stateClone
75 }
76 const queue = _pendingStates.concat()
77 this._pendingStates.length = 0
78 queue.forEach((nextState) => {
79 if (typeof nextState === 'function') {
80 nextState = nextState.call(this, stateClone, props)
81 }
82 Object.assign(stateClone, nextState)
83 })
84 return stateClone
85 }
86
87 forceUpdate (callback) {
88 if (typeof callback === 'function') {
89 (this._pendingCallbacks = this._pendingCallbacks || []).push(callback)
90 }
91 this._isForceUpdate = true
92 updateComponent(this)
93 }
94
95 $preload (key, value) {
96 const preloadData = cacheDataGet(PRELOAD_DATA_KEY) || {}
97 if (typeof key === 'object') {
98 for (const k in key) {
99 preloadData[k] = key[k]
100 }
101 } else {
102 preloadData[key] = value
103 }
104 cacheDataSet(PRELOAD_DATA_KEY, preloadData)
105 }
106
107 // 会被匿名函数调用
108 __triggerPropsFn (key, args) {
109 const keyChain = key.split('.')
110 const reduxFnPrefix = '__event_'
111 const reduxFnName = reduxFnPrefix + keyChain.shift()
112 // redux标识过的方法,直接调用
113 if (reduxFnName in this) {
114 const scope = args.shift()
115 let fn
116 if (keyChain.length > 0) {
117 fn = safeGet(this[reduxFnName], keyChain.join('.'))
118 } else {
119 fn = this[reduxFnName]
120 }
121 fn.apply(scope, args)
122 } else {
123 // 普通的
124 const keyLower = key.toLocaleLowerCase()
125 this.$scope.triggerEvent(keyLower, {
126 __isCustomEvt: true,
127 __arguments: args
128 })
129 }
130 }
131}
132
133export default BaseComponent