1- import React from 'react' ;
1+ import React , { useState , useEffect , useCallback , useRef } from 'react' ;
22import c from 'classnames' ;
33import { findDOMNode } from 'react-dom' ;
44import PropTypes from 'prop-types' ;
55import AsyncCommand from '../AsyncCommands/AsyncCommands' ;
66import { addGlobalListener } from '../../utils/browser' ;
77
8- class DropdownAsync extends React . Component {
9- constructor ( ) {
10- super ( ) ;
11- this . state = { showActions : false } ;
12- this . onOutsideClick = this . onOutsideClick . bind ( this ) ;
13- this . toggleActions = this . toggleActions . bind ( this ) ;
14- this . close = this . close . bind ( this ) ;
15- this . handleSuccess = this . handleSuccess . bind ( this ) ;
16- this . handleError = this . handleError . bind ( this ) ;
17- }
8+ const DropdownAsync = ( {
9+ config
10+ } ) => {
11+ const [ showActions , setShowActions ] = useState ( false ) ;
12+ const dropdownRef = useRef ( null ) ;
1813
19- componentDidMount ( ) {
20- this . cleanup = addGlobalListener ( 'click' , this . onOutsideClick ) ;
21- }
14+ const close = useCallback ( ( ) => {
15+ setShowActions ( false ) ;
16+ } , [ ] ) ;
2217
23- componentWillUnmount ( ) {
24- if ( this . cleanup && typeof this . cleanup === 'function' ) this . cleanup ( ) ;
25- }
18+ const onOutsideClick = useCallback ( ( e ) => {
19+ const domNode = findDOMNode ( dropdownRef . current ) ;
20+ if ( domNode && ! domNode . contains ( e . target ) ) {
21+ close ( ) ;
22+ }
23+ } , [ close ] ) ;
2624
27- onOutsideClick ( e ) {
28- if ( ! findDOMNode ( this ) . contains ( e . target ) ) this . close ( ) ;
29- }
30-
31- toggleActions ( e ) {
25+ const toggleActions = useCallback ( ( e ) => {
3226 e . preventDefault ( ) ;
3327 e . stopPropagation ( ) ;
34- this . setState ( ( prevState ) => ( {
35- showActions : ! prevState . showActions
36- } ) ) ;
37- }
38-
39- close ( ) {
40- this . setState ( { showActions : false } ) ;
41- }
28+ setShowActions ( ( prevState ) => ! prevState ) ;
29+ } , [ ] ) ;
4230
43- handleSuccess ( onSuccess ) {
44- this . close ( ) ;
31+ const handleSuccess = useCallback ( ( onSuccess ) => {
32+ close ( ) ;
4533 if ( typeof onSuccess === 'function' ) onSuccess ( ) ;
46- }
34+ } , [ close ] ) ;
4735
48- handleError ( onError ) {
49- this . close ( ) ;
36+ const handleError = useCallback ( ( onError ) => {
37+ close ( ) ;
5038 if ( typeof onError === 'function' ) onError ( ) ;
51- }
39+ } , [ close ] ) ;
5240
53- render ( ) {
54- const { config } = this . props ;
55- const { showActions } = this . state ;
56- return (
57- < div className = 'dropdown__options form-group__element--right' >
58- < button className = 'dropdown__options__btn button--green button button--small' onClick = { this . toggleActions } > < span > Options</ span > </ button >
41+ useEffect ( ( ) => {
42+ const cleanup = addGlobalListener ( 'click' , onOutsideClick ) ;
43+ return ( ) => {
44+ if ( cleanup && typeof cleanup === 'function' ) {
45+ cleanup ( ) ;
46+ }
47+ } ;
48+ } , [ onOutsideClick ] ) ;
49+
50+ return (
51+ < div className = 'dropdown__options form-group__element--right' ref = { dropdownRef } >
52+ < button className = 'dropdown__options__btn button--green button button--small' onClick = { toggleActions } > < span > Options</ span > </ button >
5953 < ul className = { c ( 'dropdown__menu' , {
6054 'dropdown__menu--hidden' : ! showActions
6155 } ) } >
6256 { config . map ( ( d ) => < li key = { d . text } >
6357 < AsyncCommand action = { d . action }
64- success = { ( ) => this . handleSuccess ( d . success ) }
65- error = { ( ) => this . handleError ( d . error ) }
58+ success = { ( ) => handleSuccess ( d . success ) }
59+ error = { ( ) => handleError ( d . error ) }
6660 status = { d . status }
6761 disabled = { d . disabled }
6862 confirmAction = { d . confirmAction }
@@ -76,9 +70,8 @@ class DropdownAsync extends React.Component {
7670 </ li > ) }
7771 </ ul >
7872 </ div >
79- ) ;
80- }
81- }
73+ ) ;
74+ } ;
8275
8376DropdownAsync . propTypes = {
8477 config : PropTypes . array
0 commit comments