Skip to content

Commit bfa9f54

Browse files
committed
Refactor Dropdown & Fix multi option removed.
1 parent 0f112b3 commit bfa9f54

File tree

1 file changed

+95
-79
lines changed

1 file changed

+95
-79
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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';
33
import ReactDropdown from 'react-virtualized-select';
44
import createFilterOptions from 'react-select-fast-filter-options';
55
import '../components/css/[email protected]';
@@ -23,88 +23,104 @@ const TOKENIZER = {
2323

2424
const DELIMITER = ',';
2525

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,
3244
tokenizer: TOKENIZER,
3345
}),
34-
};
35-
}
46+
];
47+
}, [options]);
3648

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+
);
4753

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);
7362
}
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+
};
108122

109123
Dropdown.propTypes = propTypes;
110124
Dropdown.defaultProps = defaultProps;
125+
126+
export default Dropdown;

0 commit comments

Comments
 (0)