1
- import { isNil , pluck , omit , type } from 'ramda' ;
2
- import React , { Component } from 'react' ;
1
+ import { isNil , pluck , omit , type , without } from 'ramda' ;
2
+ import React , { useState , useCallback , useEffect , useMemo } from 'react' ;
3
3
import ReactDropdown from 'react-virtualized-select' ;
4
4
import createFilterOptions from 'react-select-fast-filter-options' ;
5
5
import '../components/css/[email protected] ' ;
@@ -23,88 +23,104 @@ const TOKENIZER = {
23
23
24
24
const DELIMITER = ',' ;
25
25
26
- export default class Dropdown extends Component {
27
- constructor ( props ) {
28
- super ( props ) ;
29
- this . state = {
30
- filterOptions : createFilterOptions ( {
31
- options : sanitizeOptions ( props . options ) ,
26
+ const Dropdown = props => {
27
+ const {
28
+ id,
29
+ clearable,
30
+ multi,
31
+ options,
32
+ setProps,
33
+ style,
34
+ loading_state,
35
+ value,
36
+ } = props ;
37
+ const [ optionsCheck , setOptionsCheck ] = useState ( null ) ;
38
+ const [ sanitizedOptions , filterOptions ] = useMemo ( ( ) => {
39
+ const sanitized = sanitizeOptions ( options ) ;
40
+ return [
41
+ sanitized ,
42
+ createFilterOptions ( {
43
+ options : options ,
32
44
tokenizer : TOKENIZER ,
33
45
} ) ,
34
- } ;
35
- }
46
+ ] ;
47
+ } , [ options ] ) ;
36
48
37
- UNSAFE_componentWillReceiveProps ( newProps ) {
38
- if ( newProps . options !== this . props . options ) {
39
- this . setState ( {
40
- filterOptions : createFilterOptions ( {
41
- options : sanitizeOptions ( newProps . options ) ,
42
- tokenizer : TOKENIZER ,
43
- } ) ,
44
- } ) ;
45
- }
46
- }
49
+ const selectedValue = useMemo (
50
+ ( ) => ( type ( value ) === 'Array' ? value . join ( DELIMITER ) : value ) ,
51
+ [ value ]
52
+ ) ;
47
53
48
- render ( ) {
49
- const {
50
- id,
51
- clearable,
52
- multi,
53
- options,
54
- setProps,
55
- style,
56
- loading_state,
57
- value,
58
- } = this . props ;
59
- const { filterOptions} = this . state ;
60
- let selectedValue ;
61
- if ( type ( value ) === 'Array' ) {
62
- selectedValue = value . join ( DELIMITER ) ;
63
- } else {
64
- selectedValue = value ;
65
- }
66
- return (
67
- < div
68
- id = { id }
69
- className = "dash-dropdown"
70
- style = { style }
71
- data-dash-is-loading = {
72
- ( loading_state && loading_state . is_loading ) || undefined
54
+ const onChange = useCallback (
55
+ selectedOption => {
56
+ if ( multi ) {
57
+ let value ;
58
+ if ( isNil ( selectedOption ) ) {
59
+ value = [ ] ;
60
+ } else {
61
+ value = pluck ( 'value' , selectedOption ) ;
73
62
}
74
- >
75
- < ReactDropdown
76
- filterOptions = { filterOptions }
77
- options = { sanitizeOptions ( options ) }
78
- value = { selectedValue }
79
- onChange = { selectedOption => {
80
- if ( multi ) {
81
- let value ;
82
- if ( isNil ( selectedOption ) ) {
83
- value = [ ] ;
84
- } else {
85
- value = pluck ( 'value' , selectedOption ) ;
86
- }
87
- setProps ( { value} ) ;
88
- } else {
89
- let value ;
90
- if ( isNil ( selectedOption ) ) {
91
- value = null ;
92
- } else {
93
- value = selectedOption . value ;
94
- }
95
- setProps ( { value} ) ;
96
- }
97
- } }
98
- onInputChange = { search_value => setProps ( { search_value} ) }
99
- backspaceRemoves = { clearable }
100
- deleteRemoves = { clearable }
101
- inputProps = { { autoComplete : 'off' } }
102
- { ...omit ( [ 'setProps' , 'value' , 'options' ] , this . props ) }
103
- />
104
- </ div >
105
- ) ;
106
- }
107
- }
63
+ setProps ( { value} ) ;
64
+ } else {
65
+ let value ;
66
+ if ( isNil ( selectedOption ) ) {
67
+ value = null ;
68
+ } else {
69
+ value = selectedOption . value ;
70
+ }
71
+ setProps ( { value} ) ;
72
+ }
73
+ } ,
74
+ [ multi ]
75
+ ) ;
76
+
77
+ const onInputChange = useCallback (
78
+ search_value => setProps ( { search_value} ) ,
79
+ [ ]
80
+ ) ;
81
+
82
+ useEffect ( ( ) => {
83
+ if ( optionsCheck !== sanitizedOptions && ! isNil ( value ) ) {
84
+ const values = sanitizedOptions . map ( option => option . value ) ;
85
+ if ( multi ) {
86
+ const invalids = value . filter ( v => ! values . includes ( v ) ) ;
87
+ if ( invalids . length ) {
88
+ setProps ( { value : without ( invalids , value ) } ) ;
89
+ }
90
+ } else {
91
+ if ( ! values . includes ( selectedValue ) ) {
92
+ setProps ( { value : null } ) ;
93
+ }
94
+ }
95
+ setOptionsCheck ( sanitizedOptions ) ;
96
+ }
97
+ } , [ sanitizedOptions , optionsCheck , multi , value , selectedValue ] ) ;
98
+
99
+ return (
100
+ < div
101
+ id = { id }
102
+ className = "dash-dropdown"
103
+ style = { style }
104
+ data-dash-is-loading = {
105
+ ( loading_state && loading_state . is_loading ) || undefined
106
+ }
107
+ >
108
+ < ReactDropdown
109
+ filterOptions = { filterOptions }
110
+ options = { sanitizeOptions ( options ) }
111
+ value = { selectedValue }
112
+ onChange = { onChange }
113
+ onInputChange = { onInputChange }
114
+ backspaceRemoves = { clearable }
115
+ deleteRemoves = { clearable }
116
+ inputProps = { { autoComplete : 'of' } }
117
+ { ...omit ( [ 'setProps' , 'value' , 'options' ] , props ) }
118
+ />
119
+ </ div >
120
+ ) ;
121
+ } ;
108
122
109
123
Dropdown . propTypes = propTypes ;
110
124
Dropdown . defaultProps = defaultProps ;
125
+
126
+ export default Dropdown ;
0 commit comments