11import React , { createElement } from 'react' ;
22import PropTypes from 'prop-types' ;
33import TweenOne , { ticker } from 'rc-tween-one' ;
4+ import { polyfill } from 'react-lifecycles-compat' ;
5+
46import {
57 toArrayChildren ,
68 findChildInChildrenByKey ,
@@ -54,6 +56,108 @@ class QueueAnim extends React.Component {
5456 onEnd : noop ,
5557 appear : true ,
5658 } ;
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+ }
57161 constructor ( props ) {
58162 super ( props ) ;
59163 /**
@@ -133,6 +237,7 @@ class QueueAnim extends React.Component {
133237 this . state = {
134238 children,
135239 childrenShow,
240+ $self : this ,
136241 } ;
137242 }
138243
@@ -142,101 +247,6 @@ class QueueAnim extends React.Component {
142247 }
143248 }
144249
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-
240250 componentDidUpdate ( ) {
241251 this . originalChildren = toArrayChildren ( getChildrenFromProps ( this . props ) ) ;
242252 const keysToEnter = [ ...this . keysToEnter ] ;
@@ -550,4 +560,4 @@ class QueueAnim extends React.Component {
550560 }
551561}
552562QueueAnim . isQueueAnim = true ;
553- export default QueueAnim ;
563+ export default polyfill ( QueueAnim ) ;
0 commit comments