1+ import React from 'react' ;
12import classNames from 'classnames' ;
23import toArray from 'rc-util/lib/Children/toArray' ;
3- import * as React from 'react' ;
4- import isEqual from 'rc-util/lib/isEqual' ;
5- import type { CollapseProps , CollapsibleType } from './interface' ;
4+ import useMergedState from 'rc-util/lib/hooks/useMergedState' ;
65import CollapsePanel from './Panel' ;
6+ import type { CollapseProps , CollapsibleType } from './interface' ;
77
88function getActiveKeysArray ( activeKey : React . Key | React . Key [ ] ) {
99 let currentActiveKey = activeKey ;
@@ -15,84 +15,59 @@ function getActiveKeysArray(activeKey: React.Key | React.Key[]) {
1515 return currentActiveKey . map ( ( key ) => String ( key ) ) ;
1616}
1717
18- export interface CollapseState {
19- activeKey : React . Key [ ] ;
20- }
21-
22- class Collapse extends React . Component < CollapseProps , CollapseState > {
23- static defaultProps = {
24- prefixCls : 'rc-collapse' ,
25- onChange ( ) { } ,
26- accordion : false ,
27- destroyInactivePanel : false ,
28- } ;
29-
30- static Panel = CollapsePanel ;
31-
32- constructor ( props : CollapseProps ) {
33- super ( props ) ;
34-
35- const { activeKey, defaultActiveKey } = props ;
36- let currentActiveKey = defaultActiveKey ;
37- if ( 'activeKey' in props ) {
38- currentActiveKey = activeKey ;
39- }
40-
41- this . state = {
42- activeKey : getActiveKeysArray ( currentActiveKey ) ,
43- } ;
44- }
45-
46- shouldComponentUpdate ( nextProps : CollapseProps , nextState : CollapseState ) {
47- return ! isEqual ( this . props , nextProps , true ) || ! isEqual ( this . state , nextState , true ) ;
48- }
18+ function Collapse ( props : CollapseProps ) {
19+ const {
20+ prefixCls = 'rc-collapse' ,
21+ destroyInactivePanel = false ,
22+ style,
23+ accordion,
24+ className,
25+ children : rawChildren ,
26+ collapsible,
27+ openMotion,
28+ expandIcon,
29+ activeKey : rawActiveKey ,
30+ defaultActiveKey,
31+ onChange,
32+ } = props ;
33+
34+ const collapseClassName = classNames ( prefixCls , className ) ;
35+
36+ const [ activeKey , setActiveKey ] = useMergedState < React . Key | React . Key [ ] , React . Key [ ] > ( [ ] , {
37+ value : rawActiveKey ,
38+ onChange : ( v ) => onChange ?.( v ) ,
39+ defaultValue : defaultActiveKey ,
40+ postState : getActiveKeysArray ,
41+ } ) ;
42+
43+ const onClickItem = ( key : React . Key ) =>
44+ setActiveKey ( ( ) => {
45+ if ( accordion ) {
46+ return activeKey [ 0 ] === key ? [ ] : [ key ] ;
47+ }
4948
50- onClickItem = ( key : React . Key ) => {
51- let { activeKey } = this . state ;
52- if ( this . props . accordion ) {
53- activeKey = activeKey [ 0 ] === key ? [ ] : [ key ] ;
54- } else {
55- activeKey = [ ...activeKey ] ;
5649 const index = activeKey . indexOf ( key ) ;
5750 const isActive = index > - 1 ;
5851 if ( isActive ) {
59- // remove active state
60- activeKey . splice ( index , 1 ) ;
61- } else {
62- activeKey . push ( key ) ;
52+ return activeKey . filter ( ( item ) => item !== key ) ;
6353 }
64- }
65- this . setActiveKey ( activeKey ) ;
66- } ;
6754
68- static getDerivedStateFromProps ( nextProps : CollapseProps ) {
69- const newState : Partial < CollapseState > = { } ;
70- if ( 'activeKey' in nextProps ) {
71- newState . activeKey = getActiveKeysArray ( nextProps . activeKey ) ;
72- }
73- return newState ;
74- }
55+ return [ ...activeKey , key ] ;
56+ } ) ;
7557
76- getNewChild = ( child : React . ReactElement , index : number ) => {
58+ // ======================== Children ========================
59+ const getNewChild = ( child : React . ReactElement , index : number ) => {
7760 if ( ! child ) return null ;
7861
79- const { activeKey } = this . state ;
80- const {
81- prefixCls,
82- openMotion,
83- accordion,
84- destroyInactivePanel : rootDestroyInactivePanel ,
85- expandIcon,
86- collapsible,
87- } = this . props ;
88- // If there is no key provide, use the panel order as default key
8962 const key = child . key || String ( index ) ;
63+
9064 const {
9165 header,
9266 headerClass,
93- destroyInactivePanel,
67+ destroyInactivePanel : childDestroyInactivePanel ,
9468 collapsible : childCollapsible ,
9569 } = child . props ;
70+
9671 let isActive = false ;
9772 if ( accordion ) {
9873 isActive = activeKey [ 0 ] === key ;
@@ -102,18 +77,18 @@ class Collapse extends React.Component<CollapseProps, CollapseState> {
10277
10378 const mergeCollapsible : CollapsibleType = childCollapsible ?? collapsible ;
10479
105- const props = {
80+ const childProps = {
10681 key,
10782 panelKey : key ,
10883 header,
10984 headerClass,
11085 isActive,
11186 prefixCls,
112- destroyInactivePanel : destroyInactivePanel ?? rootDestroyInactivePanel ,
87+ destroyInactivePanel : childDestroyInactivePanel ?? destroyInactivePanel ,
11388 openMotion,
11489 accordion,
11590 children : child . props . children ,
116- onItemClick : mergeCollapsible === 'disabled' ? null : this . onClickItem ,
91+ onItemClick : mergeCollapsible === 'disabled' ? null : onClickItem ,
11792 expandIcon,
11893 collapsible : mergeCollapsible ,
11994 } ;
@@ -123,39 +98,23 @@ class Collapse extends React.Component<CollapseProps, CollapseState> {
12398 return child ;
12499 }
125100
126- Object . keys ( props ) . forEach ( ( propName : keyof typeof props ) => {
127- if ( typeof props [ propName ] === 'undefined' ) {
128- delete props [ propName ] ;
101+ Object . keys ( childProps ) . forEach ( ( propName ) => {
102+ if ( typeof childProps [ propName ] === 'undefined' ) {
103+ delete childProps [ propName ] ;
129104 }
130105 } ) ;
131106
132- return React . cloneElement ( child , props ) ;
133- } ;
134-
135- getItems = ( ) => {
136- const { children } = this . props ;
137- return toArray ( children ) . map ( this . getNewChild ) ;
107+ return React . cloneElement ( child , childProps ) ;
138108 } ;
139109
140- setActiveKey = ( activeKey : React . Key [ ] ) => {
141- if ( ! ( 'activeKey' in this . props ) ) {
142- this . setState ( { activeKey } ) ;
143- }
144- this . props . onChange ( this . props . accordion ? activeKey [ 0 ] : activeKey ) ;
145- } ;
110+ const children = toArray ( rawChildren ) . map ( getNewChild ) ;
146111
147- render ( ) {
148- const { prefixCls, className, style, accordion } = this . props ;
149- const collapseClassName = classNames ( {
150- [ prefixCls ] : true ,
151- [ className ] : ! ! className ,
152- } ) ;
153- return (
154- < div className = { collapseClassName } style = { style } role = { accordion ? 'tablist' : null } >
155- { this . getItems ( ) }
156- </ div >
157- ) ;
158- }
112+ // ======================== Render ========================
113+ return (
114+ < div className = { collapseClassName } style = { style } role = { accordion ? 'tablist' : undefined } >
115+ { children }
116+ </ div >
117+ ) ;
159118}
160119
161- export default Collapse ;
120+ export default Object . assign ( Collapse , { Panel : CollapsePanel } ) ;
0 commit comments