@@ -9,7 +9,7 @@ import useMemo from 'rc-util/lib/hooks/useMemo';
9
9
import * as React from 'react' ;
10
10
import LegacyContext from './LegacyContext' ;
11
11
import TreeSelectContext from './TreeSelectContext' ;
12
- import type { DataNode , Key , SafeKey } from './interface' ;
12
+ import type { DataNode , FieldNames , Key , SafeKey } from './interface' ;
13
13
import { getAllKeys , isCheckDisabled } from './utils/valueUtil' ;
14
14
import { useEvent } from 'rc-util' ;
15
15
import { formatStrategyValues } from './utils/strategyUtil' ;
@@ -49,7 +49,6 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
49
49
treeExpandAction,
50
50
treeTitleRender,
51
51
onPopupScroll,
52
- displayValues,
53
52
isOverMaxCount,
54
53
maxCount,
55
54
showCheckedStrategy,
@@ -84,11 +83,6 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
84
83
( prev , next ) => next [ 0 ] && prev [ 1 ] !== next [ 1 ] ,
85
84
) ;
86
85
87
- const memoRawValues = React . useMemo (
88
- ( ) => ( displayValues || [ ] ) . map ( v => v . value ) ,
89
- [ displayValues ] ,
90
- ) ;
91
-
92
86
// ========================== Values ==========================
93
87
const mergedCheckedKeys = React . useMemo ( ( ) => {
94
88
if ( ! checkable ) {
@@ -167,58 +161,69 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
167
161
// eslint-disable-next-line react-hooks/exhaustive-deps
168
162
} , [ searchValue ] ) ;
169
163
164
+ const disabledCacheRef = React . useRef ( new Map < Key , boolean > ( ) ) ;
165
+ const lastCheckedKeysRef = React . useRef < Key [ ] > ( [ ] ) ;
166
+ const lastMaxCountRef = React . useRef < number > ( null ) ;
167
+
168
+ const resetCache = React . useCallback ( ( ) => {
169
+ disabledCacheRef . current . clear ( ) ;
170
+ lastCheckedKeysRef . current = [ ...checkedKeys ] ;
171
+ lastMaxCountRef . current = maxCount ;
172
+ } , [ checkedKeys , maxCount ] ) ;
173
+
174
+ React . useEffect ( ( ) => {
175
+ resetCache ( ) ;
176
+ } , [ checkedKeys , maxCount ] ) ;
177
+
178
+ const getSelectableKeys = ( targetNode : DataNode , fieldNames : FieldNames ) : Key [ ] => {
179
+ const keys = [ targetNode [ fieldNames . value ] ] ;
180
+ if ( ! Array . isArray ( targetNode . children ) ) {
181
+ return keys ;
182
+ }
183
+
184
+ return targetNode . children . reduce ( ( acc , child ) => {
185
+ if ( ! child . disabled ) {
186
+ acc . push ( ...getSelectableKeys ( child , fieldNames ) ) ;
187
+ }
188
+ return acc ;
189
+ } , keys ) ;
190
+ } ;
191
+
170
192
const nodeDisabled = useEvent ( ( node : DataNode ) => {
171
- // Always enable selected nodes
172
- if ( checkedKeys . includes ( node [ fieldNames . value ] ) ) {
193
+ const nodeValue = node [ fieldNames . value ] ;
194
+
195
+ if ( checkedKeys . includes ( nodeValue ) ) {
173
196
return false ;
174
197
}
175
198
176
- // Get all selectable keys under current node considering conduction rules
177
- const getSelectableKeys = ( nodes : DataNode [ ] ) => {
178
- const keys : Key [ ] = [ ] ;
179
- const traverse = ( n : DataNode ) => {
180
- if ( ! n . disabled ) {
181
- keys . push ( n [ fieldNames . value ] ) ;
182
- // Only traverse children if node is not disabled
183
- if ( Array . isArray ( n . children ) ) {
184
- n . children . forEach ( traverse ) ;
185
- }
186
- }
187
- } ;
188
- nodes . forEach ( traverse ) ;
189
- return keys ;
190
- } ;
199
+ if ( isOverMaxCount ) {
200
+ return true ;
201
+ }
191
202
192
- const selectableNodeValues = getSelectableKeys ( [ node ] ) ;
203
+ const cacheKey = ` ${ nodeValue } - ${ checkedKeys . join ( ',' ) } - ${ maxCount } ` ;
193
204
194
- // Simulate checked state after selecting current node
195
- const simulatedCheckedKeys = [ ...checkedKeys , ...selectableNodeValues ] ;
205
+ // check cache
206
+ if ( disabledCacheRef . current . has ( cacheKey ) ) {
207
+ return disabledCacheRef . current . get ( cacheKey ) ;
208
+ }
196
209
210
+ // calculate disabled state
211
+ const selectableNodeKeys = getSelectableKeys ( node , fieldNames ) ;
212
+ const simulatedCheckedKeys = [ ...checkedKeys , ...selectableNodeKeys ] ;
197
213
const { checkedKeys : conductedKeys } = conductCheck ( simulatedCheckedKeys , true , keyEntities ) ;
198
-
199
- // Calculate display keys based on strategy
200
- const simulatedDisplayKeys = formatStrategyValues (
214
+ const simulatedDisplayValues = formatStrategyValues (
201
215
conductedKeys as SafeKey [ ] ,
202
216
showCheckedStrategy ,
203
217
keyEntities ,
204
218
fieldNames ,
205
219
) ;
206
220
207
- const currentDisplayKeys = formatStrategyValues (
208
- checkedKeys as SafeKey [ ] ,
209
- showCheckedStrategy ,
210
- keyEntities ,
211
- fieldNames ,
212
- ) ;
221
+ const isDisabled = simulatedDisplayValues . length > maxCount ;
213
222
214
- const newDisplayValuesCount = simulatedDisplayKeys . length - currentDisplayKeys . length ;
215
-
216
- // Check if selecting this node would exceed maxCount
217
- if ( isOverMaxCount || memoRawValues . length + newDisplayValuesCount > maxCount ) {
218
- return true ;
219
- }
223
+ // update cache
224
+ disabledCacheRef . current . set ( cacheKey , isDisabled ) ;
220
225
221
- return false ;
226
+ return isDisabled ;
222
227
} ) ;
223
228
224
229
// ========================== Get First Selectable Node ==========================
0 commit comments