1
1
import * as React from 'react' ;
2
2
import KeyCode from 'rc-util/lib/KeyCode' ;
3
+ import useMemo from 'rc-util/lib/hooks/useMemo' ;
3
4
import classNames from 'classnames' ;
4
5
import List from 'rc-virtual-list' ;
5
6
import TransBtn from './TransBtn' ;
@@ -70,6 +71,12 @@ const OptionList: React.RefForwardingComponent<
70
71
) => {
71
72
const itemPrefixCls = `${ prefixCls } -item` ;
72
73
74
+ const memoFlattenOptions = useMemo (
75
+ ( ) => flattenOptions ,
76
+ [ open , flattenOptions ] ,
77
+ ( prev , next ) => next [ 0 ] && prev [ 1 ] !== next [ 1 ] ,
78
+ ) ;
79
+
73
80
// =========================== List ===========================
74
81
const listRef = React . useRef < List > ( null ) ;
75
82
@@ -85,12 +92,12 @@ const OptionList: React.RefForwardingComponent<
85
92
86
93
// ========================== Active ==========================
87
94
const getEnabledActiveIndex = ( index : number , offset : number = 1 ) : number => {
88
- const len = flattenOptions . length ;
95
+ const len = memoFlattenOptions . length ;
89
96
90
97
for ( let i = 0 ; i < len ; i += 1 ) {
91
98
const current = ( index + i * offset + len ) % len ;
92
99
93
- const { group, data } = flattenOptions [ current ] ;
100
+ const { group, data } = memoFlattenOptions [ current ] ;
94
101
if ( ! group && ! ( data as OptionData ) . disabled ) {
95
102
return current ;
96
103
}
@@ -99,12 +106,14 @@ const OptionList: React.RefForwardingComponent<
99
106
return - 1 ;
100
107
} ;
101
108
102
- const [ activeIndex , setActiveIndex ] = React . useState ( ( ) => getEnabledActiveIndex ( 0 ) ) ;
109
+ const [ activeIndex , setActiveIndex ] = React . useState ( ( ) =>
110
+ getEnabledActiveIndex ( 0 ) ,
111
+ ) ;
103
112
const setActive = ( index : number ) => {
104
113
setActiveIndex ( index ) ;
105
114
106
115
// Trigger active event
107
- const flattenItem = flattenOptions [ index ] ;
116
+ const flattenItem = memoFlattenOptions [ index ] ;
108
117
if ( ! flattenItem ) {
109
118
onActiveValue ( null , - 1 ) ;
110
119
return ;
@@ -115,14 +124,18 @@ const OptionList: React.RefForwardingComponent<
115
124
116
125
// Auto active first item when list length or searchValue changed
117
126
React . useEffect ( ( ) => {
118
- setActive ( defaultActiveFirstOption !== false ? getEnabledActiveIndex ( 0 ) : - 1 ) ;
119
- } , [ flattenOptions . length , searchValue ] ) ;
127
+ setActive (
128
+ defaultActiveFirstOption !== false ? getEnabledActiveIndex ( 0 ) : - 1 ,
129
+ ) ;
130
+ } , [ memoFlattenOptions . length , searchValue ] ) ;
120
131
121
132
// Auto scroll to item position in single mode
122
133
React . useEffect ( ( ) => {
123
134
if ( ! multiple && open && values . size === 1 ) {
124
135
const value : RawValueType = Array . from ( values ) [ 0 ] ;
125
- const index = flattenOptions . findIndex ( ( { data } ) => ( data as OptionData ) . value === value ) ;
136
+ const index = memoFlattenOptions . findIndex (
137
+ ( { data } ) => ( data as OptionData ) . value === value ,
138
+ ) ;
126
139
setActive ( index ) ;
127
140
scrollIntoView ( index ) ;
128
141
}
@@ -156,7 +169,10 @@ const OptionList: React.RefForwardingComponent<
156
169
}
157
170
158
171
if ( offset !== 0 ) {
159
- const nextActiveIndex = getEnabledActiveIndex ( activeIndex + offset , offset ) ;
172
+ const nextActiveIndex = getEnabledActiveIndex (
173
+ activeIndex + offset ,
174
+ offset ,
175
+ ) ;
160
176
scrollIntoView ( nextActiveIndex ) ;
161
177
setActive ( nextActiveIndex ) ;
162
178
}
@@ -167,7 +183,7 @@ const OptionList: React.RefForwardingComponent<
167
183
// >>> Select
168
184
case KeyCode . ENTER : {
169
185
// value
170
- const item = flattenOptions [ activeIndex ] ;
186
+ const item = memoFlattenOptions [ activeIndex ] ;
171
187
if ( item && ! ( item . data as OptionData ) . disabled ) {
172
188
onSelectValue ( ( item . data as OptionData ) . value ) ;
173
189
} else {
@@ -191,7 +207,7 @@ const OptionList: React.RefForwardingComponent<
191
207
} ) ) ;
192
208
193
209
// ========================== Render ==========================
194
- if ( flattenOptions . length === 0 ) {
210
+ if ( memoFlattenOptions . length === 0 ) {
195
211
return (
196
212
< div
197
213
role = "listbox"
@@ -205,26 +221,35 @@ const OptionList: React.RefForwardingComponent<
205
221
}
206
222
207
223
function renderItem ( index : number ) {
208
- const item = flattenOptions [ index ] ;
224
+ const item = memoFlattenOptions [ index ] ;
209
225
const value = item && ( item . data as OptionData ) . value ;
210
226
return item ? (
211
- < div key = { index } role = "option" id = { `${ id } _list_${ index } ` } aria-selected = { values . has ( value ) } >
227
+ < div
228
+ key = { index }
229
+ role = "option"
230
+ id = { `${ id } _list_${ index } ` }
231
+ aria-selected = { values . has ( value ) }
232
+ >
212
233
{ value }
213
234
</ div >
214
235
) : null ;
215
236
}
216
237
217
238
return (
218
239
< >
219
- < div role = "listbox" id = { `${ id } _list` } style = { { height : 0 , overflow : 'hidden' } } >
240
+ < div
241
+ role = "listbox"
242
+ id = { `${ id } _list` }
243
+ style = { { height : 0 , overflow : 'hidden' } }
244
+ >
220
245
{ renderItem ( activeIndex - 1 ) }
221
246
{ renderItem ( activeIndex ) }
222
247
{ renderItem ( activeIndex + 1 ) }
223
248
</ div >
224
249
< List < SelectFlattenOptionData >
225
250
itemKey = "key"
226
251
ref = { listRef }
227
- data = { flattenOptions }
252
+ data = { memoFlattenOptions }
228
253
height = { height }
229
254
itemHeight = { itemHeight }
230
255
fullHeight = { false }
@@ -237,7 +262,9 @@ const OptionList: React.RefForwardingComponent<
237
262
// Group
238
263
if ( group ) {
239
264
return (
240
- < div className = { classNames ( itemPrefixCls , `${ itemPrefixCls } -group` ) } >
265
+ < div
266
+ className = { classNames ( itemPrefixCls , `${ itemPrefixCls } -group` ) }
267
+ >
241
268
{ label !== undefined ? label : key }
242
269
</ div >
243
270
) ;
@@ -251,15 +278,18 @@ const OptionList: React.RefForwardingComponent<
251
278
const optionPrefixCls = `${ itemPrefixCls } -option` ;
252
279
const optionClassName = classNames ( itemPrefixCls , optionPrefixCls , {
253
280
[ `${ optionPrefixCls } -grouped` ] : groupOption ,
254
- [ `${ optionPrefixCls } -active` ] : activeIndex === itemIndex && ! disabled ,
281
+ [ `${ optionPrefixCls } -active` ] :
282
+ activeIndex === itemIndex && ! disabled ,
255
283
[ `${ optionPrefixCls } -disabled` ] : disabled ,
256
284
[ `${ optionPrefixCls } -selected` ] : selected ,
257
285
} ) ;
258
286
259
287
const mergedLabel = childrenAsData ? children : label ;
260
288
261
289
const iconVisible =
262
- ! menuItemSelectedIcon || typeof menuItemSelectedIcon === 'function' || selected ;
290
+ ! menuItemSelectedIcon ||
291
+ typeof menuItemSelectedIcon === 'function' ||
292
+ selected ;
263
293
264
294
return (
265
295
< div
@@ -279,7 +309,9 @@ const OptionList: React.RefForwardingComponent<
279
309
}
280
310
} }
281
311
>
282
- < div className = { `${ optionPrefixCls } -content` } > { mergedLabel || value } </ div >
312
+ < div className = { `${ optionPrefixCls } -content` } >
313
+ { mergedLabel || value }
314
+ </ div >
283
315
{ React . isValidElement ( menuItemSelectedIcon ) || selected }
284
316
{ iconVisible && (
285
317
< TransBtn
@@ -298,9 +330,10 @@ const OptionList: React.RefForwardingComponent<
298
330
) ;
299
331
} ;
300
332
301
- const RefOptionList = React . forwardRef < RefOptionListProps , OptionListProps < SelectOptionsType > > (
302
- OptionList ,
303
- ) ;
333
+ const RefOptionList = React . forwardRef <
334
+ RefOptionListProps ,
335
+ OptionListProps < SelectOptionsType >
336
+ > ( OptionList ) ;
304
337
RefOptionList . displayName = 'OptionList' ;
305
338
306
339
export default RefOptionList ;
0 commit comments