@@ -26,56 +26,69 @@ export default class Tabs extends Component {
26
26
constructor ( props ) {
27
27
super ( props ) ;
28
28
29
- if ( this . props . selectedIndex === null ) {
30
- this . state = Tabs . copyPropsToState ( this . props , { } ) ;
31
- } else {
32
- this . state = { } ;
33
- }
29
+ this . state = Tabs . copyPropsToState ( this . props , { } ) ;
34
30
}
35
31
36
32
componentWillReceiveProps ( newProps ) {
37
- if ( this . props . selectedIndex === null ) {
38
- // Use a transactional update to prevent race conditions
39
- // when reading the state in copyPropsToState
40
- // See https://github.com/reactjs/react-tabs/issues/51
41
- this . setState ( state => Tabs . copyPropsToState ( newProps , state ) ) ;
33
+ if (
34
+ process . env . NODE_ENV !== 'production' &&
35
+ Tabs . inUncontrolledMode ( newProps ) !== Tabs . inUncontrolledMode ( this . props )
36
+ ) {
37
+ throw new Error (
38
+ `Switching between controlled mode (by using \`selectedIndex\`) and uncontrolled mode is not supported in \`Tabs\`.
39
+ For more information about controlled and uncontrolled mode of react-tabs see the README.` ,
40
+ ) ;
42
41
}
42
+ // Use a transactional update to prevent race conditions
43
+ // when reading the state in copyPropsToState
44
+ // See https://github.com/reactjs/react-tabs/issues/51
45
+ this . setState ( state => Tabs . copyPropsToState ( newProps , state ) ) ;
46
+ }
47
+
48
+ static inUncontrolledMode ( props ) {
49
+ return props . selectedIndex === null ;
43
50
}
44
51
45
52
handleSelected = ( index , last , event ) => {
46
- if ( this . state . selectedIndex != null ) {
47
- // Check if the change event handler cancels the tab change
48
- let cancel = false ;
53
+ const state = {
54
+ // Set focus if the change was triggered from the keyboard
55
+ focus : event . type === 'keydown' ,
56
+ } ;
49
57
50
- // Call change event handler
51
- if ( typeof this . props . onSelect === 'function' ) {
52
- cancel = this . props . onSelect ( index , last , event ) === false ;
53
- }
58
+ // Call change event handler
59
+ if ( typeof this . props . onSelect === 'function' ) {
60
+ // Check if the change event handler cancels the tab change
61
+ if ( this . props . onSelect ( index , last , event ) === false ) return ;
62
+ }
54
63
55
- if ( ! cancel ) {
56
- // Update selected index
57
- // Set focus if the change was triggered from the keyboard
58
- this . setState ( { selectedIndex : index , focus : event instanceof KeyboardEvent } ) ;
59
- }
64
+ if ( Tabs . inUncontrolledMode ( this . props ) ) {
65
+ // Update selected index
66
+ state . selectedIndex = index ;
60
67
}
68
+
69
+ this . setState ( state ) ;
61
70
}
62
71
63
72
// preserve the existing selectedIndex from state.
64
73
// If the state has not selectedIndex, default to the defaultIndex or 0
65
74
static copyPropsToState ( props , state ) {
66
- const maxTabIndex = getTabsCount ( props . children ) - 1 ;
67
- let selectedIndex = null ;
75
+ const newState = {
76
+ focus : state . focus || props . defaultFocus ,
77
+ } ;
78
+
79
+ if ( Tabs . inUncontrolledMode ( props ) ) {
80
+ const maxTabIndex = getTabsCount ( props . children ) - 1 ;
81
+ let selectedIndex = null ;
68
82
69
- if ( state . selectedIndex != null ) {
70
- selectedIndex = Math . min ( state . selectedIndex , maxTabIndex ) ;
71
- } else {
72
- selectedIndex = props . defaultIndex || 0 ;
83
+ if ( state . selectedIndex != null ) {
84
+ selectedIndex = Math . min ( state . selectedIndex , maxTabIndex ) ;
85
+ } else {
86
+ selectedIndex = props . defaultIndex || 0 ;
87
+ }
88
+ newState . selectedIndex = selectedIndex ;
73
89
}
74
90
75
- return {
76
- selectedIndex,
77
- focus : state . focus || props . defaultFocus ,
78
- } ;
91
+ return newState ;
79
92
}
80
93
81
94
render ( ) {
@@ -100,9 +113,10 @@ export default class Tabs extends Component {
100
113
101
114
const { children, defaultIndex, defaultFocus, ...props } = this . props ;
102
115
116
+ props . focus = this . state . focus ;
117
+ props . onSelect = this . handleSelected ;
118
+
103
119
if ( this . state . selectedIndex != null ) {
104
- props . focus = this . state . focus ;
105
- props . onSelect = this . handleSelected ;
106
120
props . selectedIndex = this . state . selectedIndex ;
107
121
}
108
122
0 commit comments