-
-
Save leocristofani/98312e61807db8f32e720c9f97a186e5 to your computer and use it in GitHub Desktop.
import React, { PropTypes } from 'react'; | |
import Select from 'react-select'; | |
import 'react-select/dist/react-select.css'; | |
RFReactSelect.defaultProps = { | |
multi: false, | |
className: "" | |
}; | |
RFReactSelect.propTypes = { | |
input: PropTypes.shape({ | |
name: PropTypes.string.isRequired, | |
value: PropTypes.string.isRequired, | |
onBlur: PropTypes.func.isRequired, | |
onChange: PropTypes.func.isRequired, | |
onFocus: PropTypes.func.isRequired, | |
}).isRequired, | |
options: PropTypes.array.isRequired, | |
multi: PropTypes.bool, | |
className: PropTypes.string | |
}; | |
export default function RFReactSelect({ input , options, multi, className }) { | |
const { name, value, onBlur, onChange, onFocus } = input; | |
const transformedValue = transformValue(value, options, multi); | |
return ( | |
<Select | |
valueKey="value" | |
name={name} | |
value={transformedValue} | |
multi={multi} | |
options={options} | |
onChange={multi | |
? multiChangeHandler(onChange) | |
: singleChangeHandler(onChange) | |
} | |
onBlur={() => onBlur(value)} | |
onFocus={onFocus} | |
className={className} | |
/> | |
); | |
} | |
/** | |
* onChange from Redux Form Field has to be called explicity. | |
*/ | |
function singleChangeHandler(func) { | |
return function handleSingleChange(value) { | |
func(value ? value.value : ''); | |
}; | |
} | |
/** | |
* onBlur from Redux Form Field has to be called explicity. | |
*/ | |
function multiChangeHandler(func) { | |
return function handleMultiHandler(values) { | |
func(values.map(value => value.value)); | |
}; | |
} | |
/** | |
* For single select, Redux Form keeps the value as a string, while React Select | |
* wants the value in the form { value: "grape", label: "Grape" } | |
* | |
* * For multi select, Redux Form keeps the value as array of strings, while React Select | |
* wants the array of values in the form [{ value: "grape", label: "Grape" }] | |
*/ | |
function transformValue(value, options, multi) { | |
if (multi && typeof value === 'string') return []; | |
const filteredOptions = options.filter(option => { | |
return multi | |
? value.indexOf(option.value) !== -1 | |
: option.value === value; | |
}); | |
return multi ? filteredOptions : filteredOptions[0]; | |
} |
@bionicvapourboy trying putting simpleValue: true
in your Select
component to get [555-333444, ....]
in your state instead of [{label:'555-3333444', key:'555-333444'}, {label:...., value:....}....]
Hey @leocristofani, thank you for this, it is great.
For multi-select inputs, I am getting an error at value: PropTypes.string.isRequired
(L13). The component is expecting a string, but Redux Form and React Select both require arrays (note on L66-67).
Perhaps the following would be better:
RFReactSelect.propTypes = {
input: PropTypes.shape({
...
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.array,
]).isRequired,
...
}).isRequired,
...
};
https://github.com/erikras/redux-form/blob/ca00a778af5e2ca5079fc9cac153bd33dd1e313d/src/ConnectedField.js#L106-L110 I have some problems because of this piece of code.
Because onChange doesn't receive event object but just a plain value, my custom onChange receives this weird construct. I can bypass it by setting a new onCustomChange callback which is called by your handleSingleValue
, but if anybody has a better idea, I'd appreciate it.
I was able to run Creatable successfully by decorating the options parameter before the render function of my custom input component Field.
let values = input.value.split(',');
values.map(value => {
if(Boolean(value) && !_find(options, {value})) {
options.push({label: value, value});
}
});
thanks :) you saved my day 👍
Thank you for sharing the amazing work. After reading every post out there on react-select/redux-form, this is the only one that works for me. I'm trying to get a default value set, but I'm unsure where to put it. The pattern seems to be to have 'value' come from the component's state, and update that state onChange. I've been playing around with changing export default function RFReactSelect
to a full React.Component
so I can give it state, but haven't been able to get it right. Any suggestions?
Thank you!
I'm using react 15.4.1
, redux-form 7.0.1
and react-select 2.0.0
. I've used your code and still got the same problem: values
were cleaned from store after the blur event.
Found out, that the onBlur={() => onBlur(value)}
override was not needed. After I had removed this line, it started working well! Thanks for the handy snippet!
With the introduction of "actionMeta". How can we incorporate it in "multiChangeHandler" to get the meta information like "name" of the field in our custom onchangehandler?
Currently this is how we have to make it run
handleChangeCreatable = (newValue, actionMeta, prevValue, name) => {
this.setState({
[name]: newValue
});
};
@gurmeetsinghmalhotra thanks for your comment, but I no longer maintain this gist since I moved away from using Redux and Redux Form long ago. Best of luck!
@terencechow same problem, partially solved:
<Field multi name="phones" options={phones} component={RFReactSelect} />
and
The only issue left is about how react-select saves data in redux form state:
[{label:'555-3333444', key:'555-333444'}, {label:...., value:....}....]
instead of
[555-333444, ....]
Forcing onBlur to pass a plain array to the redux state of the form make the component unable to render from state.