1
1
/* eslint-disable react-hooks/exhaustive-deps */
2
- import React , { useEffect , useReducer } from 'react' ;
2
+ import React from 'react' ;
3
3
4
4
import PropTypes from 'prop-types' ;
5
5
import clsx from 'clsx' ;
6
- import isEqual from 'lodash/isEqual' ;
7
- import fnToString from '../utils/fn-to-string' ;
8
- import reducer , { init } from './reducer' ;
9
- import useIsMounted from '../hooks/use-is-mounted' ;
10
-
11
- const getSelectValue = ( stateValue , simpleValue , isMulti , allOptions ) => {
12
- let enhancedValue = stateValue ;
13
-
14
- let hasSelectAll = isMulti && allOptions . find ( ( { selectAll } ) => selectAll ) ;
15
- let hasSelectNone = isMulti && allOptions . find ( ( { selectNone } ) => selectNone ) ;
16
-
17
- if ( hasSelectAll || hasSelectNone ) {
18
- enhancedValue = enhancedValue || [ ] ;
19
- const optionsLength = allOptions . filter (
20
- ( { selectAll, selectNone, divider, options } ) => ! selectAll && ! selectNone && ! divider && ! options
21
- ) . length ;
22
-
23
- const selectedAll = optionsLength === enhancedValue . length ;
24
- const selectedNone = enhancedValue . length === 0 ;
25
-
26
- enhancedValue = [
27
- ...enhancedValue ,
28
- ...( hasSelectAll && selectedAll ? [ simpleValue ? hasSelectAll . value : hasSelectAll ] : [ ] ) ,
29
- ...( hasSelectNone && selectedNone ? [ simpleValue ? hasSelectNone . value : hasSelectNone ] : [ ] ) ,
30
- ] ;
31
- }
32
-
33
- return simpleValue ? allOptions . filter ( ( { value } ) => ( isMulti ? enhancedValue . includes ( value ) : isEqual ( value , enhancedValue ) ) ) : enhancedValue ;
34
- } ;
35
-
36
- const handleSelectChange = ( option , simpleValue , isMulti , onChange , allOptions , removeSelectAll , removeSelectNone ) => {
37
- let enhanceOption = option ;
38
-
39
- if ( removeSelectNone ) {
40
- enhanceOption = enhanceOption . filter ( ( { selectNone } ) => ! selectNone ) ;
41
- } else if ( removeSelectAll ) {
42
- enhanceOption = enhanceOption . filter ( ( { selectAll } ) => ! selectAll ) ;
43
- }
44
-
45
- const sanitizedOption = ! enhanceOption && isMulti ? [ ] : enhanceOption ;
46
-
47
- if ( isMulti && sanitizedOption . find ( ( { selectAll } ) => selectAll ) ) {
48
- return onChange ( allOptions . filter ( ( { selectAll, selectNone, value } ) => ! selectAll && ! selectNone && value ) . map ( ( { value } ) => value ) ) ;
49
- }
50
-
51
- if ( isMulti && sanitizedOption . find ( ( { selectNone } ) => selectNone ) ) {
52
- return onChange ( [ ] ) ;
53
- }
54
-
55
- return simpleValue
56
- ? onChange ( isMulti ? sanitizedOption . map ( ( item ) => item . value ) : sanitizedOption ? sanitizedOption . value : undefined )
57
- : onChange ( sanitizedOption ) ;
58
- } ;
6
+ import useSelect from '../use-select/use-select' ;
59
7
60
8
const Select = ( {
61
9
invalid,
@@ -78,57 +26,25 @@ const Select = ({
78
26
optionsTransformer,
79
27
...props
80
28
} ) => {
81
- const [ state , originalDispatch ] = useReducer ( reducer , { optionsTransformer, propsOptions } , init ) ;
82
- const dispatch = ( action ) => originalDispatch ( { ...action , optionsTransformer } ) ;
83
-
84
- const isMounted = useIsMounted ( ) ;
85
-
86
- const updateOptions = ( ) => {
87
- dispatch ( { type : 'startLoading' } ) ;
88
-
89
- return loadOptions ( ) . then ( ( data ) => {
90
- if ( isMounted . current ) {
91
- if ( ! noValueUpdates ) {
92
- if ( value && Array . isArray ( value ) ) {
93
- const selectValue = value . filter ( ( value ) =>
94
- typeof value === 'object' ? data . find ( ( option ) => value . value === option . value ) : data . find ( ( option ) => value === option . value )
95
- ) ;
96
- onChange ( selectValue . length === 0 ? undefined : selectValue ) ;
97
- } else if ( value && ! data . find ( ( { value : internalValue } ) => internalValue === value ) ) {
98
- onChange ( undefined ) ;
99
- }
100
- }
101
-
102
- dispatch ( { type : 'updateOptions' , payload : data } ) ;
103
- }
104
- } ) ;
105
- } ;
106
-
107
- useEffect ( ( ) => {
108
- if ( loadOptions ) {
109
- updateOptions ( ) ;
110
- }
111
-
112
- dispatch ( { type : 'initialLoaded' } ) ;
113
- } , [ ] ) ;
114
-
115
- const loadOptionsStr = loadOptions ? fnToString ( loadOptions ) : '' ;
116
-
117
- useEffect ( ( ) => {
118
- if ( loadOptionsStr && state . isInitialLoaded ) {
119
- updateOptions ( ) ;
120
- }
121
- } , [ loadOptionsStr , loadOptionsChangeCounter ] ) ;
122
-
123
- useEffect ( ( ) => {
124
- if ( state . isInitialLoaded ) {
125
- if ( ! noValueUpdates && value && ! propsOptions . map ( ( { value } ) => value ) . includes ( value ) ) {
126
- onChange ( undefined ) ;
127
- }
128
-
129
- dispatch ( { type : 'setOptions' , payload : propsOptions } ) ;
130
- }
131
- } , [ propsOptions ] ) ;
29
+ const {
30
+ state,
31
+ value : selectValue ,
32
+ onChange : selectOnChange ,
33
+ onInputChange,
34
+ isFetching,
35
+ } = useSelect ( {
36
+ loadOptions,
37
+ optionsTransformer,
38
+ options : propsOptions ,
39
+ noValueUpdates,
40
+ onChange,
41
+ value,
42
+ loadOptionsChangeCounter,
43
+ isSearchable : props . isSearchable ,
44
+ pluckSingleValue,
45
+ isMulti,
46
+ simpleValue,
47
+ } ) ;
132
48
133
49
const renderNoOptionsMessage = ( ) => ( Object . values ( state . promises ) . some ( ( value ) => value ) ? ( ) => updatingMessage : ( ) => noOptionsMessage ) ;
134
50
@@ -149,34 +65,6 @@ const Select = ({
149
65
) ;
150
66
}
151
67
152
- const onInputChange = ( inputValue ) => {
153
- if ( inputValue && loadOptions && state . promises [ inputValue ] === undefined && props . isSearchable ) {
154
- dispatch ( { type : 'setPromises' , payload : { [ inputValue ] : true } } ) ;
155
-
156
- loadOptions ( inputValue )
157
- . then ( ( options ) => {
158
- if ( isMounted . current ) {
159
- dispatch ( {
160
- type : 'setPromises' ,
161
- payload : { [ inputValue ] : false } ,
162
- options,
163
- } ) ;
164
- }
165
- } )
166
- . catch ( ( error ) => {
167
- dispatch ( { type : 'setPromises' , payload : { [ inputValue ] : false } } ) ;
168
- // eslint-disable-next-line no-console
169
- console . error ( error ) ;
170
- } ) ;
171
- }
172
- } ;
173
-
174
- const selectValue = pluckSingleValue ? ( isMulti ? value : Array . isArray ( value ) && value [ 0 ] ? value [ 0 ] : value ) : value ;
175
-
176
- const filteredLength = state . options . filter ( ( { selectAll, selectNone } ) => ! selectAll && ! selectNone ) . length ;
177
- const shouldRemoveSelectAll = isMulti && state . options . find ( ( { selectAll } ) => selectAll ) && selectValue . length === filteredLength ;
178
- const shouldRemoveSelectNone = isMulti && state . options . find ( ( { selectNone } ) => selectNone ) && selectValue . length === 0 ;
179
-
180
68
return (
181
69
< SelectComponent
182
70
className = { clsx ( classNamePrefix , {
@@ -187,10 +75,10 @@ const Select = ({
187
75
options = { state . options }
188
76
classNamePrefix = { classNamePrefix }
189
77
isMulti = { isMulti }
190
- value = { getSelectValue ( selectValue , simpleValue , isMulti , state . options ) }
191
- onChange = { ( option ) => handleSelectChange ( option , simpleValue , isMulti , onChange , state . options , shouldRemoveSelectAll , shouldRemoveSelectNone ) }
78
+ value = { selectValue }
79
+ onChange = { selectOnChange }
192
80
onInputChange = { onInputChange }
193
- isFetching = { Object . values ( state . promises ) . some ( ( value ) => value ) }
81
+ isFetching = { isFetching }
194
82
noOptionsMessage = { renderNoOptionsMessage ( ) }
195
83
hideSelectedOptions = { false }
196
84
closeMenuOnSelect = { ! isMulti }
0 commit comments