1
+ import React from 'react' ;
1
2
import classNames from 'classnames' ;
2
3
import 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' ;
6
5
import CollapsePanel from './Panel' ;
6
+ import type { CollapseProps , CollapsibleType } from './interface' ;
7
7
8
8
function getActiveKeysArray ( activeKey : React . Key | React . Key [ ] ) {
9
9
let currentActiveKey = activeKey ;
@@ -15,84 +15,59 @@ function getActiveKeysArray(activeKey: React.Key | React.Key[]) {
15
15
return currentActiveKey . map ( ( key ) => String ( key ) ) ;
16
16
}
17
17
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
+ }
49
48
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 ] ;
56
49
const index = activeKey . indexOf ( key ) ;
57
50
const isActive = index > - 1 ;
58
51
if ( isActive ) {
59
- // remove active state
60
- activeKey . splice ( index , 1 ) ;
61
- } else {
62
- activeKey . push ( key ) ;
52
+ return activeKey . filter ( ( item ) => item !== key ) ;
63
53
}
64
- }
65
- this . setActiveKey ( activeKey ) ;
66
- } ;
67
54
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
+ } ) ;
75
57
76
- getNewChild = ( child : React . ReactElement , index : number ) => {
58
+ // ======================== Children ========================
59
+ const getNewChild = ( child : React . ReactElement , index : number ) => {
77
60
if ( ! child ) return null ;
78
61
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
89
62
const key = child . key || String ( index ) ;
63
+
90
64
const {
91
65
header,
92
66
headerClass,
93
- destroyInactivePanel,
67
+ destroyInactivePanel : childDestroyInactivePanel ,
94
68
collapsible : childCollapsible ,
95
69
} = child . props ;
70
+
96
71
let isActive = false ;
97
72
if ( accordion ) {
98
73
isActive = activeKey [ 0 ] === key ;
@@ -102,18 +77,18 @@ class Collapse extends React.Component<CollapseProps, CollapseState> {
102
77
103
78
const mergeCollapsible : CollapsibleType = childCollapsible ?? collapsible ;
104
79
105
- const props = {
80
+ const childProps = {
106
81
key,
107
82
panelKey : key ,
108
83
header,
109
84
headerClass,
110
85
isActive,
111
86
prefixCls,
112
- destroyInactivePanel : destroyInactivePanel ?? rootDestroyInactivePanel ,
87
+ destroyInactivePanel : childDestroyInactivePanel ?? destroyInactivePanel ,
113
88
openMotion,
114
89
accordion,
115
90
children : child . props . children ,
116
- onItemClick : mergeCollapsible === 'disabled' ? null : this . onClickItem ,
91
+ onItemClick : mergeCollapsible === 'disabled' ? null : onClickItem ,
117
92
expandIcon,
118
93
collapsible : mergeCollapsible ,
119
94
} ;
@@ -123,39 +98,23 @@ class Collapse extends React.Component<CollapseProps, CollapseState> {
123
98
return child ;
124
99
}
125
100
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 ] ;
129
104
}
130
105
} ) ;
131
106
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 ) ;
138
108
} ;
139
109
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 ) ;
146
111
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
+ ) ;
159
118
}
160
119
161
- export default Collapse ;
120
+ export default Object . assign ( Collapse , { Panel : CollapsePanel } ) ;
0 commit comments