@@ -4,8 +4,8 @@ import type { DFormControl } from '../form';
44import type { DSelectOption } from '../select' ;
55import type { AbstractTreeNode } from '../tree' ;
66
7- import { isArray , isNull } from 'lodash' ;
8- import React , { useCallback , useMemo , useState , useId , useRef } from 'react' ;
7+ import { isNull } from 'lodash' ;
8+ import React , { useCallback , useState , useId , useMemo } from 'react' ;
99
1010import { usePrefixConfig , useComponentConfig , useGeneralContext , useDValue , useEventNotify } from '../../hooks' ;
1111import { LoadingOutlined } from '../../icons' ;
@@ -14,8 +14,7 @@ import { DSelectbox } from '../_selectbox';
1414import { DDropdown } from '../dropdown' ;
1515import { useFormControl } from '../form' ;
1616import { DTag } from '../tag' ;
17- import { useTreeData } from '../tree' ;
18- import { SingleTreeNode , MultipleTreeNode } from '../tree' ;
17+ import { MultipleTreeNode , SingleTreeNode } from '../tree' ;
1918import { DList } from './List' ;
2019import { DSearchList } from './SearchList' ;
2120import { getText , TREE_NODE_KEY } from './utils' ;
@@ -108,86 +107,67 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(
108107 const listId = `${ dPrefix } cascader-list-${ uniqueId } ` ;
109108 const getOptionId = ( val : V ) => `${ dPrefix } cascader-option-${ val } -${ uniqueId } ` ;
110109
110+ const renderNodes = useMemo (
111+ ( ) =>
112+ dOptions . map ( ( option ) =>
113+ dMultiple
114+ ? new MultipleTreeNode ( option , ( o ) => o . value , {
115+ disabled : option . disabled ,
116+ } )
117+ : new SingleTreeNode ( option , ( o ) => o . value , {
118+ disabled : option . disabled ,
119+ } )
120+ ) ,
121+ [ dMultiple , dOptions ]
122+ ) ;
123+ const nodesMap = useMemo ( ( ) => {
124+ const nodes = new Map < V , AbstractTreeNode < V , T > > ( ) ;
125+ const reduceArr = ( arr : AbstractTreeNode < V , T > [ ] ) => {
126+ for ( const item of arr ) {
127+ nodes . set ( item . id , item ) ;
128+ if ( item . children ) {
129+ reduceArr ( item . children ) ;
130+ }
131+ }
132+ } ;
133+ reduceArr ( renderNodes ) ;
134+ return nodes ;
135+ } , [ renderNodes ] ) ;
136+
111137 const [ searchValue , setSearchValue ] = useState ( '' ) ;
112138
113139 const [ visible , changeVisible ] = useDValue < boolean > ( false , dVisible , onVisibleChange ) ;
114140 const formControlInject = useFormControl ( dFormControl ) ;
115- const [ select , changeSelect ] = useDValue < V | null | V [ ] > (
141+ const [ _select , changeSelect ] = useDValue < V | null | V [ ] > (
116142 dMultiple ? [ ] : null ,
117143 dModel ,
118144 ( value ) => {
119145 if ( onModelChange ) {
120- if ( isArray ( value ) ) {
121- let length = value . length ;
122- const options : DNestedChildren < T > [ ] = [ ] ;
123- const reduceArr = ( arr : DNestedChildren < T > [ ] ) => {
124- for ( const item of arr ) {
125- if ( length === 0 ) {
126- break ;
127- }
128- if ( item . children ) {
129- reduceArr ( item . children ) ;
130- } else {
131- const index = value . findIndex ( ( val ) => val === item . value ) ;
132- if ( index !== - 1 ) {
133- options [ index ] = item ;
134- length -= 1 ;
135- }
136- }
137- }
138- } ;
139- reduceArr ( dOptions ) ;
140-
141- onModelChange ( value , options ) ;
146+ if ( dMultiple ) {
147+ onModelChange (
148+ value ,
149+ ( value as V [ ] ) . map ( ( v ) => nodesMap . get ( v ) ?. origin )
150+ ) ;
142151 } else {
143- if ( isNull ( value ) ) {
144- onModelChange ( value , null ) ;
145- } else {
146- onModelChange (
147- value ,
148- findNested ( dOptions , ( option ) => option . value === value )
149- ) ;
150- }
152+ onModelChange ( value , isNull ( value ) ? null : nodesMap . get ( value as V ) ?. origin ) ;
151153 }
152154 }
153155 } ,
154156 undefined ,
155157 formControlInject
156158 ) ;
159+ const select = useMemo ( ( ) => ( dMultiple ? new Set ( _select as V [ ] ) : ( _select as V | null ) ) , [ _select , dMultiple ] ) ;
160+ renderNodes . forEach ( ( node ) => {
161+ node . updateStatus ( select ) ;
162+ } ) ;
157163
158164 const size = dSize ?? gSize ;
159165 const disabled = dDisabled || gDisabled || dFormControl ?. control . disabled ;
160166
161167 const hasSearch = searchValue . length > 0 ;
162- const hasSelected = dMultiple ? ( select as V [ ] ) . length > 0 : ! isNull ( select ) ;
163-
164- const checkedRef = useRef < SingleTreeNode < V , T > > ( ) ;
165- const getRenderNodes = useCallback (
166- ( select : V | null | V [ ] ) => {
167- let renderNodes : SingleTreeNode < V , T > [ ] | MultipleTreeNode < V , T > [ ] = [ ] ;
168- if ( dMultiple ) {
169- renderNodes = dOptions . map (
170- ( option ) =>
171- new MultipleTreeNode ( option , ( o ) => o . value , {
172- checkeds : select as V [ ] ,
173- disabled : option . disabled ,
174- } )
175- ) ;
176- } else {
177- renderNodes = dOptions . map (
178- ( option ) =>
179- new SingleTreeNode ( option , ( o ) => o . value , {
180- checkedRef,
181- checked : select as V | null ,
182- disabled : option . disabled ,
183- } )
184- ) ;
185- }
186- return renderNodes ;
187- } ,
188- [ dMultiple , dOptions ]
189- ) ;
190- const [ renderNodes , changeSelectByCache ] = useTreeData ( select , getRenderNodes , changeSelect ) ;
168+ const hasSelected = dMultiple ? ( select as Set < V > ) . size > 0 : ! isNull ( select ) ;
169+
170+ const [ focusVisible , setFocusVisible ] = useState ( false ) ;
191171
192172 const filterFn = useCallback (
193173 ( option : T , searchStr = searchValue ) => {
@@ -199,7 +179,7 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(
199179 [ dCustomSearch , searchValue ]
200180 ) ;
201181 const sortFn = dCustomSearch ?. sort ;
202- const searchOptions = useMemo ( ( ) => {
182+ const searchOptions = ( ( ) => {
203183 if ( ! hasSearch ) {
204184 return [ ] ;
205185 }
@@ -228,40 +208,32 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(
228208 searchOptions . sort ( ( a , b ) => sortFn ( a [ TREE_NODE_KEY ] . origin , b [ TREE_NODE_KEY ] . origin ) ) ;
229209 }
230210 return searchOptions ;
231- } , [ dMultiple , dOnlyLeafSelectable , filterFn , hasSearch , renderNodes , sortFn ] ) ;
232-
233- const [ focusVisible , setFocusVisible ] = useState ( false ) ;
211+ } ) ( ) ;
234212
235213 const [ _noSearchFocusNode , setNoSearchFocusNode ] = useState < AbstractTreeNode < V , T > | undefined > ( ) ;
236- const noSearchFocusNode = useMemo ( ( ) => {
237- if (
238- _noSearchFocusNode &&
239- findNested ( renderNodes as AbstractTreeNode < V , T > [ ] , ( node ) => node . enabled && node . id === _noSearchFocusNode . id )
240- ) {
241- return _noSearchFocusNode ;
214+ const noSearchFocusNode = ( ( ) => {
215+ if ( _noSearchFocusNode ) {
216+ const node = nodesMap . get ( _noSearchFocusNode . id ) ;
217+ if ( node && node . enabled ) {
218+ return node ;
219+ }
242220 }
243221
244- if ( isArray ( select ) ) {
245- if ( select . length > 0 ) {
246- return findNested ( renderNodes as AbstractTreeNode < V , T > [ ] , ( node ) => node . enabled && node . checked ) ;
247- }
248- } else {
249- if ( ! isNull ( select ) ) {
250- return findNested ( renderNodes as AbstractTreeNode < V , T > [ ] , ( node ) => node . enabled && node . checked ) ;
251- }
222+ if ( hasSelected ) {
223+ return findNested ( renderNodes as AbstractTreeNode < V , T > [ ] , ( node ) => node . enabled && node . checked ) ;
252224 }
253- } , [ _noSearchFocusNode , renderNodes , select ] ) ;
225+ } ) ( ) ;
254226
255227 const [ _searchFocusOption , setSearchFocusOption ] = useState < DSearchOption < V , T > | undefined > ( ) ;
256- const searchFocusOption = useMemo ( ( ) => {
228+ const searchFocusOption = ( ( ) => {
257229 if ( _searchFocusOption && findNested ( searchOptions , ( o ) => o [ TREE_NODE_KEY ] . enabled && o . value === _searchFocusOption . value ) ) {
258230 return _searchFocusOption ;
259231 }
260232
261233 if ( hasSearch ) {
262234 return findNested ( searchOptions , ( o ) => o [ TREE_NODE_KEY ] . enabled ) ;
263235 }
264- } , [ _searchFocusOption , hasSearch , searchOptions ] ) ;
236+ } ) ( ) ;
265237
266238 const handleClear = ( ) => {
267239 onClear ?.( ) ;
@@ -273,30 +245,12 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(
273245 }
274246 } ;
275247
276- const [ selectedNode , suffixNode , selectedLabel ] = useMemo ( ( ) => {
248+ const [ selectedNode , suffixNode , selectedLabel ] = ( ( ) => {
277249 let selectedNode : React . ReactNode = null ;
278250 let suffixNode : React . ReactNode = null ;
279251 let selectedLabel : string | undefined ;
280252 if ( dMultiple ) {
281- const selectedNodes : MultipleTreeNode < V , T > [ ] = [ ] ;
282- let length = ( select as V [ ] ) . length ;
283- const reduceArr = ( arr : MultipleTreeNode < V , T > [ ] ) => {
284- for ( const item of arr ) {
285- if ( length === 0 ) {
286- break ;
287- }
288- if ( item . children ) {
289- reduceArr ( item . children ) ;
290- } else {
291- const index = ( select as V [ ] ) . findIndex ( ( val ) => val === item . id ) ;
292- if ( index !== - 1 ) {
293- selectedNodes [ index ] = item ;
294- length -= 1 ;
295- }
296- }
297- }
298- } ;
299- reduceArr ( renderNodes as MultipleTreeNode < V , T > [ ] ) ;
253+ const selectedNodes = ( _select as V [ ] ) . map ( ( v ) => nodesMap . get ( v ) as MultipleTreeNode < V , T > ) ;
300254
301255 suffixNode = (
302256 < DDropdown
@@ -314,12 +268,12 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(
314268 } ) }
315269 dCloseOnClick = { false }
316270 onOptionClick = { ( id , option ) => {
317- const checkeds = ( option . node as MultipleTreeNode < V , T > ) . changeStatus ( 'UNCHECKED' , select as V [ ] ) ;
318- changeSelectByCache ( checkeds ) ;
271+ const checkeds = ( option . node as MultipleTreeNode < V , T > ) . changeStatus ( 'UNCHECKED' , select as Set < V > ) ;
272+ changeSelect ( Array . from ( checkeds . keys ( ) ) ) ;
319273 } }
320274 >
321275 < DTag className = { `${ dPrefix } cascader__multiple-count` } dSize = { size } >
322- { ( select as V [ ] ) . length }
276+ { ( select as Set < V > ) . size }
323277 </ DTag >
324278 </ DDropdown >
325279 ) ;
@@ -332,24 +286,22 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(
332286 onClose = { ( e ) => {
333287 e . stopPropagation ( ) ;
334288
335- const checkeds = ( node as MultipleTreeNode < V , T > ) . changeStatus ( 'UNCHECKED' , select as V [ ] ) ;
336- changeSelectByCache ( checkeds ) ;
289+ const checkeds = ( node as MultipleTreeNode < V , T > ) . changeStatus ( 'UNCHECKED' , select as Set < V > ) ;
290+ changeSelect ( Array . from ( checkeds . keys ( ) ) ) ;
337291 } }
338292 >
339293 { dCustomSelected ? dCustomSelected ( node . origin ) : node . origin . label }
340294 </ DTag >
341295 ) ) ;
342296 } else {
343297 if ( ! isNull ( select ) ) {
344- const node = findNested ( renderNodes as SingleTreeNode < V , T > [ ] , ( node ) => node . id === ( select as V ) ) ;
345- if ( node ) {
346- selectedLabel = getText ( node ) ;
347- selectedNode = dCustomSelected ? dCustomSelected ( node . origin ) : selectedLabel ;
348- }
298+ const node = nodesMap . get ( select as V ) ! ;
299+ selectedLabel = getText ( node ) ;
300+ selectedNode = dCustomSelected ? dCustomSelected ( node . origin ) : selectedLabel ;
349301 }
350302 }
351303 return [ selectedNode , suffixNode , selectedLabel ] ;
352- } , [ changeSelectByCache , dCustomSelected , dMultiple , dPrefix , disabled , renderNodes , select , size ] ) ;
304+ } ) ( ) ;
353305
354306 return (
355307 < DSelectbox
@@ -419,10 +371,10 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(
419371 { dLoading && (
420372 < div
421373 className = { getClassName ( `${ dPrefix } cascader__loading` , {
422- [ `${ dPrefix } cascader__loading--empty` ] : dOptions . length === 0 ,
374+ [ `${ dPrefix } cascader__loading--empty` ] : ( hasSearch ? searchOptions : renderNodes ) . length === 0 ,
423375 } ) }
424376 >
425- < LoadingOutlined dSize = { dOptions . length === 0 ? 18 : 24 } dSpin />
377+ < LoadingOutlined dSize = { ( hasSearch ? searchOptions : renderNodes ) . length === 0 ? 18 : 24 } dSpin />
426378 </ div >
427379 ) }
428380 { hasSearch ? (
@@ -436,7 +388,7 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(
436388 dMultiple = { dMultiple }
437389 dOnlyLeafSelectable = { dOnlyLeafSelectable }
438390 dFocusVisible = { focusVisible }
439- onSelectedChange = { changeSelectByCache }
391+ onSelectedChange = { changeSelect }
440392 onClose = { ( ) => {
441393 changeVisible ( false ) ;
442394 } }
@@ -459,7 +411,7 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(
459411 dOnlyLeafSelectable = { dOnlyLeafSelectable }
460412 dFocusVisible = { focusVisible }
461413 dRoot
462- onSelectedChange = { changeSelectByCache }
414+ onSelectedChange = { changeSelect }
463415 onClose = { ( ) => {
464416 changeVisible ( false ) ;
465417 } }
0 commit comments