1
1
import React , { createElement } from 'react' ;
2
2
import PropTypes from 'prop-types' ;
3
3
import TweenOne , { ticker } from 'rc-tween-one' ;
4
+ import { polyfill } from 'react-lifecycles-compat' ;
5
+
4
6
import {
5
7
toArrayChildren ,
6
8
findChildInChildrenByKey ,
@@ -54,6 +56,108 @@ class QueueAnim extends React.Component {
54
56
onEnd : noop ,
55
57
appear : true ,
56
58
} ;
59
+
60
+ static getDerivedStateFromProps ( props , { prevProps, children, childrenShow : prevChildShow , $self } ) {
61
+ const nextState = {
62
+ prevProps : props ,
63
+ } ;
64
+ const prevChildren = prevProps ? toArrayChildren ( prevProps . children ) . filter ( c => c ) : [ ] ;
65
+ const nextChildren = toArrayChildren ( props . children ) . filter ( c => c ) ;
66
+ if ( prevProps &&
67
+ prevChildren . map ( c => c . key ) . join ( ) !== nextChildren . map ( c => c . key ) . join ( )
68
+ ) {
69
+ let currentChildren = $self . originalChildren . filter ( item => item ) ;
70
+ if ( children . length ) {
71
+ /**
72
+ * 多次刷新处理
73
+ * 如果 state.children 里还有元素,元素还在动画,当前子级加回在出场的子级;
74
+ */
75
+ const leaveChild = children . filter (
76
+ item => item && $self . keysToLeave . indexOf ( item . key ) >= 0 ,
77
+ ) ;
78
+ $self . leaveUnfinishedChild = leaveChild . map ( item => item . key ) ;
79
+ /**
80
+ * 获取 leaveChild 在 state.children 里的序列,再将 leaveChild 和 currentChildren 的重新排序。
81
+ * 避逸 state.children 在 leaveComplete 里没全部完成不触发,
82
+ * leaveComplete 里如果动画完成了是会删除 keyToLeave,但 state.children 是在全部出场后才触发清除,
83
+ * 所以这里需要处理出场完成的元素做清除。
84
+ */
85
+ const stateChildren = mergeChildren ( currentChildren , children ) ;
86
+ const currentChild = [ ] ;
87
+ const childReOrder = child => {
88
+ child . forEach ( item => {
89
+ const order = stateChildren . indexOf ( item ) ;
90
+ // -1 不应该出现的情况,直接插入数组后面.
91
+ if ( order === - 1 ) {
92
+ currentChild . push ( item ) ;
93
+ } else {
94
+ currentChild . splice ( order , 0 , item ) ;
95
+ }
96
+ } ) ;
97
+ } ;
98
+ childReOrder ( leaveChild ) ;
99
+ childReOrder ( currentChildren ) ;
100
+ currentChildren = currentChild . filter ( c => c ) ;
101
+ }
102
+ const newChildren = mergeChildren ( currentChildren , nextChildren ) ;
103
+
104
+ const childrenShow = ! newChildren . length ? { } : prevChildShow ;
105
+ $self . keysToEnterPaused = { } ;
106
+ const emptyBool = ! nextChildren . length && ! currentChildren . length && children . length ;
107
+ /**
108
+ * 在出场没结束时,childrenShow 里的值将不会清除。
109
+ * 再触发进场时, childrenShow 里的值是保留着的, 设置了 forcedReplay 将重新播放进场。
110
+ */
111
+ if ( ! emptyBool ) {
112
+ // 空子级状态下刷新不做处理
113
+ const nextKeys = nextChildren . map ( c => c . key ) ;
114
+ $self . keysToLeave . forEach ( key => {
115
+ // 将所有在出场里的停止掉。避免间隔性出现
116
+ if ( nextKeys . indexOf ( key ) >= 0 ) {
117
+ $self . keysToEnterPaused [ key ] = true ;
118
+ currentChildren = currentChildren . filter ( item => item . key !== key ) ;
119
+ if ( props . forcedReplay ) {
120
+ // 清掉所有出场的。
121
+ delete childrenShow [ key ] ;
122
+ }
123
+ }
124
+ } ) ;
125
+ }
126
+
127
+ $self . keysToEnter = [ ] ;
128
+ $self . keysToLeave = [ ] ;
129
+
130
+ // need render to avoid update
131
+ nextState . childrenShow = childrenShow ;
132
+ nextState . children = newChildren ;
133
+
134
+ nextChildren . forEach ( c => {
135
+ if ( ! c ) {
136
+ return ;
137
+ }
138
+ const key = c . key ;
139
+ const hasPrev = findChildInChildrenByKey ( currentChildren , key ) ;
140
+ if ( ! hasPrev && key ) {
141
+ $self . keysToEnter . push ( key ) ;
142
+ }
143
+ } ) ;
144
+
145
+ currentChildren . forEach ( c => {
146
+ if ( ! c ) {
147
+ return ;
148
+ }
149
+ const key = c . key ;
150
+ const hasNext = findChildInChildrenByKey ( nextChildren , key ) ;
151
+ if ( ! hasNext && key ) {
152
+ $self . keysToLeave . push ( key ) ;
153
+ ticker . clear ( $self . placeholderTimeoutIds [ key ] ) ;
154
+ delete $self . placeholderTimeoutIds [ key ] ;
155
+ }
156
+ } ) ;
157
+ $self . keysToEnterToCallback = [ ...$self . keysToEnter ] ;
158
+ }
159
+ return nextState ;
160
+ }
57
161
constructor ( props ) {
58
162
super ( props ) ;
59
163
/**
@@ -133,6 +237,7 @@ class QueueAnim extends React.Component {
133
237
this . state = {
134
238
children,
135
239
childrenShow,
240
+ $self : this ,
136
241
} ;
137
242
}
138
243
@@ -142,101 +247,6 @@ class QueueAnim extends React.Component {
142
247
}
143
248
}
144
249
145
- componentWillReceiveProps ( nextProps ) {
146
- const nextChildren = toArrayChildren ( nextProps . children ) . filter ( item => item ) ;
147
- let currentChildren = this . originalChildren . filter ( item => item ) ;
148
- if ( this . state . children . length ) {
149
- /**
150
- * 多次刷新处理
151
- * 如果 state.children 里还有元素,元素还在动画,当前子级加回在出场的子级;
152
- */
153
- const leaveChild = this . state . children . filter (
154
- item => item && this . keysToLeave . indexOf ( item . key ) >= 0 ,
155
- ) ;
156
- this . leaveUnfinishedChild = leaveChild . map ( item => item . key ) ;
157
- /**
158
- * 获取 leaveChild 在 state.children 里的序列,再将 leaveChild 和 currentChildren 的重新排序。
159
- * 避逸 state.children 在 leaveComplete 里没全部完成不触发,
160
- * leaveComplete 里如果动画完成了是会删除 keyToLeave,但 state.children 是在全部出场后才触发清除,
161
- * 所以这里需要处理出场完成的元素做清除。
162
- */
163
- const stateChildrens = mergeChildren ( currentChildren , this . state . children ) ;
164
- const currentChild = [ ] ;
165
- const childReOrder = child => {
166
- child . forEach ( item => {
167
- const order = stateChildrens . indexOf ( item ) ;
168
- // -1 不应该出现的情况,直接插入数组后面.
169
- if ( order === - 1 ) {
170
- currentChild . push ( item ) ;
171
- } else {
172
- currentChild . splice ( order , 0 , item ) ;
173
- }
174
- } ) ;
175
- } ;
176
- childReOrder ( leaveChild ) ;
177
- childReOrder ( currentChildren ) ;
178
- currentChildren = currentChild . filter ( c => c ) ;
179
- }
180
- const newChildren = mergeChildren ( currentChildren , nextChildren ) ;
181
-
182
- const childrenShow = ! newChildren . length ? { } : this . state . childrenShow ;
183
- this . keysToEnterPaused = { } ;
184
- const emptyBool = ! nextChildren . length && ! currentChildren . length && this . state . children . length ;
185
- /**
186
- * 在出场没结束时,childrenShow 里的值将不会清除。
187
- * 再触发进场时, childrenShow 里的值是保留着的, 设置了 forcedReplay 将重新播放进场。
188
- */
189
- if ( ! emptyBool ) {
190
- // 空子级状态下刷新不做处理
191
- const nextKeys = nextChildren . map ( c => c . key ) ;
192
- this . keysToLeave . forEach ( key => {
193
- // 将所有在出场里的停止掉。避免间隔性出现
194
- if ( nextKeys . indexOf ( key ) >= 0 ) {
195
- this . keysToEnterPaused [ key ] = true ;
196
- currentChildren = currentChildren . filter ( item => item . key !== key ) ;
197
- if ( nextProps . forcedReplay ) {
198
- // 清掉所有出场的。
199
- delete childrenShow [ key ] ;
200
- }
201
- }
202
- } ) ;
203
- }
204
-
205
- this . keysToEnter = [ ] ;
206
- this . keysToLeave = [ ] ;
207
-
208
- // need render to avoid update
209
- this . setState ( {
210
- childrenShow,
211
- children : newChildren ,
212
- } ) ;
213
-
214
- nextChildren . forEach ( c => {
215
- if ( ! c ) {
216
- return ;
217
- }
218
- const key = c . key ;
219
- const hasPrev = findChildInChildrenByKey ( currentChildren , key ) ;
220
- if ( ! hasPrev && key ) {
221
- this . keysToEnter . push ( key ) ;
222
- }
223
- } ) ;
224
-
225
- currentChildren . forEach ( c => {
226
- if ( ! c ) {
227
- return ;
228
- }
229
- const key = c . key ;
230
- const hasNext = findChildInChildrenByKey ( nextChildren , key ) ;
231
- if ( ! hasNext && key ) {
232
- this . keysToLeave . push ( key ) ;
233
- ticker . clear ( this . placeholderTimeoutIds [ key ] ) ;
234
- delete this . placeholderTimeoutIds [ key ] ;
235
- }
236
- } ) ;
237
- this . keysToEnterToCallback = [ ...this . keysToEnter ] ;
238
- }
239
-
240
250
componentDidUpdate ( ) {
241
251
this . originalChildren = toArrayChildren ( getChildrenFromProps ( this . props ) ) ;
242
252
const keysToEnter = [ ...this . keysToEnter ] ;
@@ -550,4 +560,4 @@ class QueueAnim extends React.Component {
550
560
}
551
561
}
552
562
QueueAnim . isQueueAnim = true ;
553
- export default QueueAnim ;
563
+ export default polyfill ( QueueAnim ) ;
0 commit comments