@@ -9,7 +9,7 @@ import useMemo from 'rc-util/lib/hooks/useMemo';
99import * as React from 'react' ;
1010import LegacyContext from './LegacyContext' ;
1111import TreeSelectContext from './TreeSelectContext' ;
12- import type { DataNode , Key , SafeKey } from './interface' ;
12+ import type { DataNode , FieldNames , Key , SafeKey } from './interface' ;
1313import { getAllKeys , isCheckDisabled } from './utils/valueUtil' ;
1414import { useEvent } from 'rc-util' ;
1515import { formatStrategyValues } from './utils/strategyUtil' ;
@@ -49,7 +49,6 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
4949 treeExpandAction,
5050 treeTitleRender,
5151 onPopupScroll,
52- displayValues,
5352 isOverMaxCount,
5453 maxCount,
5554 showCheckedStrategy,
@@ -84,11 +83,6 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
8483 ( prev , next ) => next [ 0 ] && prev [ 1 ] !== next [ 1 ] ,
8584 ) ;
8685
87- const memoRawValues = React . useMemo (
88- ( ) => ( displayValues || [ ] ) . map ( v => v . value ) ,
89- [ displayValues ] ,
90- ) ;
91-
9286 // ========================== Values ==========================
9387 const mergedCheckedKeys = React . useMemo ( ( ) => {
9488 if ( ! checkable ) {
@@ -167,58 +161,69 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
167161 // eslint-disable-next-line react-hooks/exhaustive-deps
168162 } , [ searchValue ] ) ;
169163
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+
170192 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 ) ) {
173196 return false ;
174197 }
175198
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+ }
191202
192- const selectableNodeValues = getSelectableKeys ( [ node ] ) ;
203+ const cacheKey = ` ${ nodeValue } - ${ checkedKeys . join ( ',' ) } - ${ maxCount } ` ;
193204
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+ }
196209
210+ // calculate disabled state
211+ const selectableNodeKeys = getSelectableKeys ( node , fieldNames ) ;
212+ const simulatedCheckedKeys = [ ...checkedKeys , ...selectableNodeKeys ] ;
197213 const { checkedKeys : conductedKeys } = conductCheck ( simulatedCheckedKeys , true , keyEntities ) ;
198-
199- // Calculate display keys based on strategy
200- const simulatedDisplayKeys = formatStrategyValues (
214+ const simulatedDisplayValues = formatStrategyValues (
201215 conductedKeys as SafeKey [ ] ,
202216 showCheckedStrategy ,
203217 keyEntities ,
204218 fieldNames ,
205219 ) ;
206220
207- const currentDisplayKeys = formatStrategyValues (
208- checkedKeys as SafeKey [ ] ,
209- showCheckedStrategy ,
210- keyEntities ,
211- fieldNames ,
212- ) ;
221+ const isDisabled = simulatedDisplayValues . length > maxCount ;
213222
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 ) ;
220225
221- return false ;
226+ return isDisabled ;
222227 } ) ;
223228
224229 // ========================== Get First Selectable Node ==========================
0 commit comments