1- import React , { Component , MouseEventHandler } from 'react' ;
1+ import * as React from 'react' ;
22import classNames from 'classnames' ;
33
44export type SwitchChangeEventHandler = ( checked : boolean , event : MouseEvent ) => void ;
@@ -11,7 +11,7 @@ interface SwitchProps {
1111 checkedChildren ?: React . ReactNode ;
1212 unCheckedChildren ?: React . ReactNode ;
1313 onChange ?: SwitchChangeEventHandler ;
14- onMouseUp : MouseEventHandler < HTMLButtonElement > ;
14+ onMouseUp : React . MouseEventHandler < HTMLButtonElement > ;
1515 onClick ?: SwitchClickEventHandler ;
1616 tabIndex ?: number ;
1717 checked ?: boolean ;
@@ -22,143 +22,115 @@ interface SwitchProps {
2222 title ?: string ;
2323}
2424
25- interface SwitchState {
26- checked : boolean ;
27- }
28-
29- class Switch extends Component < SwitchProps , SwitchState > {
30- private node : React . RefObject < HTMLButtonElement > ;
25+ const Switch = React . forwardRef < HTMLButtonElement , SwitchProps > ( ( props , ref ) => {
26+ const mergedRef = ( ref as any ) || React . createRef < HTMLButtonElement > ( ) ;
3127
32- static defaultProps = {
33- prefixCls : 'rc-switch' ,
34- checkedChildren : null ,
35- unCheckedChildren : null ,
36- className : '' ,
37- defaultChecked : false ,
38- } ;
39-
40- constructor ( props ) {
41- super ( props ) ;
42- let checked = false ;
43- if ( 'checked' in props ) {
44- checked = ! ! props . checked ;
45- } else {
46- checked = ! ! props . defaultChecked ;
47- }
48- this . state = { checked } ;
49- this . node = React . createRef ( ) ;
28+ let initChecked = false ;
29+ if ( 'checked' in props ) {
30+ initChecked = ! ! props . checked ;
31+ } else {
32+ initChecked = ! ! props . defaultChecked ;
5033 }
34+ const [ checked , setChecked ] = React . useState ( initChecked ) ;
5135
52- componentDidMount ( ) {
53- const { autoFocus, disabled } = this . props ;
36+ React . useEffect ( ( ) => {
37+ const { autoFocus, disabled } = props ;
5438 if ( autoFocus && ! disabled ) {
55- this . focus ( ) ;
39+ focus ( ) ;
5640 }
57- }
41+ } , [ props . autoFocus , props . disabled ] ) ;
5842
59- static getDerivedStateFromProps ( nextProps ) {
60- const { checked } = nextProps ;
61- const newState : Partial < SwitchState > = { } ;
62- if ( 'checked' in nextProps ) {
63- newState . checked = ! ! checked ;
43+ React . useEffect ( ( ) => {
44+ if ( 'checked' in props ) {
45+ setChecked ( ! ! props . checked ) ;
6446 }
65- return newState ;
66- }
47+ } , [ props . checked ] ) ;
6748
68- setChecked ( checked , e ) {
69- const { disabled, onChange } = this . props ;
49+ const setInternalChecked = ( checked , e ) => {
50+ const { disabled, onChange } = props ;
7051 if ( disabled ) {
7152 return ;
7253 }
73- if ( ! ( 'checked' in this . props ) ) {
74- this . setState ( {
75- checked,
76- } ) ;
54+ if ( ! ( 'checked' in props ) ) {
55+ setChecked ( checked ) ;
7756 }
7857 if ( onChange ) {
7958 onChange ( checked , e ) ;
8059 }
81- }
60+ } ;
8261
83- handleClick = e => {
84- const { checked } = this . state ;
85- const { onClick } = this . props ;
62+ const handleClick = e => {
63+ const { onClick } = props ;
8664 const newChecked = ! checked ;
87- this . setChecked ( newChecked , e ) ;
65+ setInternalChecked ( newChecked , e ) ;
8866 if ( onClick ) {
8967 onClick ( newChecked , e ) ;
9068 }
9169 } ;
9270
93- handleKeyDown = e => {
71+ const handleKeyDown = e => {
9472 if ( e . keyCode === 37 ) {
9573 // Left
96- this . setChecked ( false , e ) ;
74+ setInternalChecked ( false , e ) ;
9775 } else if ( e . keyCode === 39 ) {
9876 // Right
99- this . setChecked ( true , e ) ;
77+ setInternalChecked ( true , e ) ;
10078 }
10179 } ;
10280
10381 // Handle auto focus when click switch in Chrome
104- handleMouseUp = e => {
105- const { onMouseUp } = this . props ;
106- this . blur ( ) ;
107- if ( onMouseUp ) {
108- onMouseUp ( e ) ;
82+ const handleMouseUp = e => {
83+ ( mergedRef . current as any ) . blur ( ) ;
84+ if ( props . onMouseUp ) {
85+ props . onMouseUp ( e ) ;
10986 }
11087 } ;
11188
112- focus ( ) {
113- if ( this . node . current ) {
114- this . node . current . focus ( ) ;
115- }
116- }
117-
118- blur ( ) {
119- if ( this . node . current ) {
120- this . node . current . blur ( ) ;
121- }
122- }
123-
124- render ( ) {
125- const {
126- className,
127- prefixCls,
128- disabled,
129- loadingIcon,
130- checkedChildren,
131- unCheckedChildren,
132- onChange,
133- ...restProps
134- } = this . props ;
135- const { checked } = this . state ;
136- const switchClassName = classNames ( {
137- [ className ] : ! ! className ,
138- [ prefixCls ] : true ,
139- [ `${ prefixCls } -checked` ] : checked ,
140- [ `${ prefixCls } -disabled` ] : disabled ,
141- } ) ;
142- return (
143- < button
144- { ...restProps }
145- type = "button"
146- role = "switch"
147- aria-checked = { checked }
148- disabled = { disabled }
149- className = { switchClassName }
150- ref = { this . node }
151- onKeyDown = { this . handleKeyDown }
152- onClick = { this . handleClick }
153- onMouseUp = { this . handleMouseUp }
154- >
155- { loadingIcon }
156- < span className = { `${ prefixCls } -inner` } >
157- { checked ? checkedChildren : unCheckedChildren }
158- </ span >
159- </ button >
160- ) ;
161- }
162- }
89+ const {
90+ className,
91+ prefixCls,
92+ disabled,
93+ loadingIcon,
94+ checkedChildren,
95+ unCheckedChildren,
96+ onChange,
97+ ...restProps
98+ } = props ;
99+
100+ const switchClassName = classNames ( {
101+ [ className ] : ! ! className ,
102+ [ prefixCls ] : true ,
103+ [ `${ prefixCls } -checked` ] : checked ,
104+ [ `${ prefixCls } -disabled` ] : disabled ,
105+ } ) ;
106+
107+ return (
108+ < button
109+ { ...restProps }
110+ type = "button"
111+ role = "switch"
112+ aria-checked = { checked }
113+ disabled = { disabled }
114+ className = { switchClassName }
115+ ref = { mergedRef }
116+ onKeyDown = { handleKeyDown }
117+ onClick = { handleClick }
118+ onMouseUp = { handleMouseUp }
119+ >
120+ { loadingIcon }
121+ < span className = { `${ prefixCls } -inner` } > { checked ? checkedChildren : unCheckedChildren } </ span >
122+ </ button >
123+ ) ;
124+ } ) ;
125+
126+ Switch . displayName = 'Switch' ;
127+
128+ Switch . defaultProps = {
129+ prefixCls : 'rc-switch' ,
130+ checkedChildren : null ,
131+ unCheckedChildren : null ,
132+ className : '' ,
133+ defaultChecked : false ,
134+ } ;
163135
164136export default Switch ;
0 commit comments