Hi, aswome work!, i am trying to use this with react-select but when the control loses focus it also loses its value, is there a way to make redux-form play ball with react-select ?
Can you show me your action history from redux-devtools? If the BLUR action is passing undefined as the value, then there's a chance that this is already fixed as of v1.6.3.
it's showing value:"" i managed to make it work by doing onBlur={this.fix.bind(this) on the Select component and this.props.fields.myfield.handleBlur(item.value); on the fix handler, but it feels like a hack.
Yes, that's pretty disgusting. If react-select is setting the value to "" onBlur, that seems like a bug with that library. How on earth could that be an intentional feature?
Well, it works fine if used by itself, it only loses the value once integrated with redux-form. it seems that the blur event needs to be handled a little different.
On my "hack", is there a different way to do this? a more official way? i am quite new to redux, thanks!
@erikras , i was looking into this, in my hack item.value is undefined.... the event has no values inside, i was just feeding undefined to the redux-form handleBlur but that made it preserve the value
I'm not entirely sure that I understand your "hack". What is the structure of the BLUR action both with and without your hack?
my "hack" did nothing, its equivalent to just sending nothing in this.props.fields.myfield.handleBlur() the event onBlur={this.fix.bind(this) in the handler is there but contains no values
I finally got around to implementing a react-select component with redux-form. I have a component that is wrapping <Select/>, and I've got:
render() {
const {value, onBlur, ...props} = this.props;
return <Select
value={value || ''} // because react-select doesn't like the initial value of undefined
onBlur={() => onBlur(value)} // just pass the current value (updated on change) on blur
{...props}/>;
}
In my opinion both of these are shortcomings of react-select. The onBlur is passing the event where the event.target is the input, which has already been cleared of its value, so event.target.value === ''. If I were the author of react-select, I'd populate that value to give the illusion that my component was just like any other standard input.
CC: @JedWatson
@erikras onBlur is undefined for me it works if i do
onBlur={() =>handleBlur(value)}
(one curiosity is that value is undefined as far as i can tell)
but an issue remains, if i also use the onChange event (that i need to set the initial value of another component upon selection) the value gets rest back to the older value after blur, my form as ts a multiple record form, perhaps i am making a mistake?
Sorry, my code in the last comment was unclear. Here (omitting imports and propTypes):
// MyForm.js
@connectReduxForm({
form: 'myFrom',
fields: ['myField']
})
export default class MyForm extends Component {
submitValues(values) {
console.log('values submitted', values); // send to server
}
render() {
const {handleSubmit, fields: {myField}} = this.props;
return (<form onSubmit={handleSubmit(this.submitValues.bind(this))}>
<MySelectComponent {...myField} options={optionsFromSomewhere}/>
<button onClick={handleSubmit(this.submitValues.bind(this))}>Submit</button>
</form>);
}
}
// MySelectComponent.js
export default class MySelectComponent extends Component {
render() {
const {value, onBlur, ...props} = this.props; // onBlur and value was on this.props.fields.myField in MyForm
return <Select
value={value || ''} // because react-select doesn't like the initial value of undefined
onBlur={() => onBlur(value)} // just pass the current value (updated on change) on blur
{...props}/>; // options are part of other props
}
}
If you follow that structure, onBlur should really be defined.
As for your "older value" concern, the value is updated on every change and the updated value is re-passed as a prop, so whenever blur occurs, the value of value should be the most recent one given to onChange.
Does that help at all?
yup, i does, it works now, i also needed to hook into the on change event so i did this:
onSelectChange (value){
this.props.fields.pertinetFiled.handleChange(value); //pertinentField is the field that this select is 'bound'
this.props.fields.someOtherField.handleChange(someValue); //i am changing another select element here
}
for now its working fine, i think its ok to do it this way, but it you have suggestions i would love to hear it.
kind regards
That's acceptable.
I _could_ potentially rig up something similar to the plugin() interface that would allow the initialization of field2 based on a CHANGE action for field1, thus making the whole operation atomic with just the single action. I'll keep that in mind for a possible future feature.
normalize() almost does this, as well.
@erikras thanks for the mention. I'll open an issue on react-select to update the blur event, I think that's a sane approach; I haven't used onBlur to grab a value before so hadn't considered that use case.
Will open one for the undefined value thing as well, that sounds like a bug.
EDIT: (react-select < 1.0) For those coming to this issue, if you use multiselect with key-value pairs, This is what I had to do
export default class MySelectComponent extends Component {
render() {
const { value, onChange, onBlur, ...props } = this.props
return (
<Select
{...props}
value={value || ''}
onBlur={() => {}}
onChange={(val, items) => onChange(items)}
/>
)
}
}
passing in the full array set on change, otherwise it only grabs the value and doesn't display the proper label when passing in your updated props on change.
@erikras maybe the onBlur can check arguments.length and if it was called without any arguments it can keep the value it had? I'm seeing the same with a datepicker and I presume many components don't think of implementing onBlur correctly...
Good thinking, @wmertens.
@wmertens Looking at the code, it really looks like if you pass nothing to onBlur() it's not going to update the value in the store, it's just going to mark that field as unfocused.
Confirmed. Calling onBlur() will not change the value in the store.
any news on this one? seems like its closed and the changes need to be done on react-select itself?
@mmahalwy I'm using react-select 1.0.0-beta8 with very few issues. I believe react-select handles null values now the new version.
<Select
name={this.props.field.name}
value={value}
options={options}
onChange={::this.onChange}
onBlur={() => this.props.field.onBlur(this.props.field.value)}
placeholder={this.props.placeholder}
noResultsText={this.state.noResultsText}
disabled={this.props.submitting} />
@eventhough i'm struggling with this. if the above is a snippet from a wrapper component, can you provide the code for the entire component, and maybe even an example of the form itself?
Bumping this as it still seems pretty unclear how to integrate these. In particular I think we need an example of a working onChange handler. Is this handler expected to dispatch a message to update the store? Some example components would be very helpful.
@tony-kerz @sslotsky Sorry for the slow response. I took a look at my component and I ended up writing a custom onChange handler that sets the value of my select input to null when it receives an empty string. Does this help?
Also I am still using v3.x.x of redux-form. I haven't upgraded yet to v4.
onChange(option) {
if (option) {
this.props.field.onChange(option.value);
} else {
this.props.field.onChange(null);
}
if (this.props.onChangeValue) {
this.props.onChangeValue(option);
}
}
<Select
name={this.props.field.name}
value={value}
options={options}
onChange={::this.onChange}
onBlur={() => this.props.field.onBlur(this.props.field.value)}
placeholder={this.props.placeholder}
noResultsText={this.state.noResultsText}
disabled={this.props.submitting} />
My experience before trying your change:
My experience after trying your change:
Now, I do suspect one factor in this to be CSS. The styles don't mesh with my app and it might be interfering with my ability to interact with the list of options. Using the arrow keys does nothing, and the list shows up stacked behind the form elements underneath it. Sadly I see no general guidelines on styling this thing. However, that doesn't explain why the option stays in Scenario 1 Step 2, but does not stay in Scenario 2.
Any advice appreciated.
Ah, I may as well paste the code for my components.
export class SelectAsync extends React.Component {
static propTypes = {
field: PropTypes.object.isRequired,
id: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
load: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
serverErrors: PropTypes.array
};
render() {
const {
field,
id,
label,
load,
onChange,
serverErrors
} = this.props;
return (
<FormField {...this.props}>
<Select.Async
id={id}
loadOptions={_.debounce(load, 1000)}
{...field}
onChange={this.onChange}
onBlur={() => field.onBlur(field.value)}
className="form-control" />
</FormField>
);
}
}
export class KitProductFields extends React.Component {
static propTypes = {
kitProduct: PropTypes.object.isRequired,
loadProducts: PropTypes.func.isRequired,
serverErrors: PropTypes.array.isRequired
};
onProductSelect(option) {
const {product_sku} = this.props.kit_product;
let val = option && option.value || null;
product_sku.onChange(val);
}
render() {
const {
kitProduct: {price, product_sku},
serverErrors,
loadProducts
} = this.props;
return (
<div>
<SelectAsync
field={product_sku}
id={product_sku.name}
label={'Product'}
load={loadProducts}
onChange={::this.onProductSelect} />
<TextField
field={price}
id={price.name}
label={'Price'}
serverErrors={serverErrors} />
</div>
);
}
}
Update on the above - I resolved the styling issue and am able to interact with the list.
Unfortunately, the problems are still exactly as I described them before. In Scenario 1, my selection is retained until I tab away from the field. In Scenario 2, my selection is not retained at all.
Interestingly, it seems to be working when I remove the onChange event and use only the onBlur
Thanks @sslotsky. That solved the issue for me.
It doesn't work for me, any one has any idea?
I used "react-select": "^1.0.0-beta13",
"redux-form": "^4.2.0",
Thanks,
Hi @sslotsky , I tried your code and removed onChange event, but, it still doesn't work for me. Do you have any idea please?
Here is my code
import React, {Component,PropTypes} from 'react';
import {connect} from 'react-redux';
import Select from 'react-select';
import {getInvoiceMonth} from '../api/invoiceRepository';
const mapStateToProps=(store)=>{
return {invoiceMonth:store.invoice.month};
};
class InvoiceMonthList extends Component{
constructor(props) {
super(props);
};
componentWillMount(){
this.props.getInvoiceMonth();
}
render() {
const {invoiceMonth,fields,onBlur,onChange,id}=this.props;
const options=this.props.invoiceMonth.map(month=>({label:month.invoicePeriod,value:month.invoicePeriod}));
return (
<Select id={id} onBlur={() => fields.onBlur(fields.value)} {...fields} options={options} />
);
}
}
InvoiceMonthList.propTypes={
invoiceMonth: PropTypes.array.isRequired,
fields: PropTypes.object.isRequired,
id: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
};
export default connect(mapStateToProps,{getInvoiceMonth})(InvoiceMonthList);
class Index extends Component{
constructor(props) {
super(props);
};
onMonthChange(option){
const {period}=this.props.fields;
let val=option && option.value || null;
period.onChange(val);
}
render() {
const {custInvoices,handleSubmit, fields: { type, period }}=this.props;
return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))} className="form-horizontal col-xs-12 col-sm-12 col-md-12">
</div>
</div>
</div>
</form>
);
}
}
For those struggling with the new Field API and react-select or react-material-ui.
Here is a working example with react-material-ui (should be same thing with react-select)
class RenderSelectInput extends Component {
onChange(evt, index, value) {
if (this.props.input.onChange) {
this.props.input.onChange(value);
}
}
render() {
return (
<SelectField {...this.props.input} value={this.props.input.value || ''} onBlur={() => this.props.input.onBlur(this.props.input.value)} onChange={this.onChange.bind(this)}>
<MenuItem value={1} primaryText="a"/>
<MenuItem value={2} primaryText="b"/>
<MenuItem value={3} primaryText="c"/>
</SelectField>
);
}
};
Then simply declare your field:
<Field name="status" component={RenderSelectInput}/>
If you want to make it even more generic, you can use:
class RenderSelectInput extends Component {
onChange(evt, index, value) {
if (this.props.input.onChange) {
this.props.input.onChange(value);
}
}
render() {
return (
<SelectField {...this.props.input} value={this.props.input.value || ''}
onBlur={() => this.props.input.onBlur(this.props.input.value)}
onChange={this.onChange.bind(this)}>
{this.props.children}
</SelectField>
);
}
}
with
<Field name="family" component={props =>
<RenderSelectInput {...props}>
<MenuItem value={1} primaryText="a"/>
<MenuItem value={2} primaryText="b"/>
<MenuItem value={3} primaryText="c"/>
</RenderSelectInput>
}/>
Can not clean value if using focus method to another DOM element. I think that is a bug.
onReactSelectChange (inputValue) {
this.setState({
value: ''
});
this.refs.geoSuggest.focus(); //- that is another element
}
Then maybe should be added blur method ........ not only focus
I have Select and Select.Async working with rc4. Here is what I use for Select:
static handleSelect(field) {
const { input, label, meta, options } = field;
const selectProps = {
onBlur: (event) => {
field.input.value = input.value;
},
onChange: (option) => {
field.input.onChange(option);// option.value, option.label
},
options,
}
return (
<FormField key={`${input.name}`}>
<FormFieldLabel>{label}</FormFieldLabel>
<Select
{...input}
{...selectProps}
/>
{meta.touched && meta.error &&
<span className="form-error is-visible">{meta.error}</span>}
{field.help && <FormFieldHelp>{field.help}</FormFieldHelp>}
</FormField>
);
}
If anyone still wants to plug react-select to redux-form, I tried @GuillaumeCisco 's solution and based on this kind of found a way to make it work (but it looks hack-ish):
// SelectInput.js
import React, {Component, PropTypes} from 'react'
import Select from 'react-select'
class SelectInput extends Component {
onChange(event) {
if (this.props.input.onChange) {
this.props.input.onChange(event.value); // <-- To be aligned with how redux-form publishes its CHANGE action payload. The event received is an object with 2 keys: "value" and "label"
}
}
render() {
return (
<Select
{...this.props}
value={this.props.input.value || ''}
onBlur={() => this.props.input.onBlur(this.props.input.value)}
onChange={this.onChange.bind(this)}
options={this.props.options} // <-- Receive options from the form
/>
);
}
}
export default SelectInput
// WhateverReduxForm.js
import SelectInput from './SelectInput'
// stuff before
<Field
name="myReduxFormFieldName"
component={props =>
<SelectInput
{...props}
options={[
{value: '0', label: 'First option'},
{value: '1', label: 'Second option'}
]}
/>
}
/>
// stuff after
This seems to work. The only issue I'm still facing is that the dropdown width "jumps" depending on if I have focus on it, this remains to be investigated.
I hope it can help someone.
@Sir4ur0n beware of using the fat arrow right here:
component={props =>
See the "breaking change" here: https://github.com/erikras/redux-form/releases/tag/v6.0.0-alpha.14
It may be causing the jumping you're describing.
@Aaronius Thank you for the heads up, I wasn't aware of that.
Anyway I found out the root cause for my issue: I now use autosize={false} prop on my Select element. By default autosize is set to true, which was most likely the root of the jumping.
@Sir4ur0n
Your solution works fine for single values. But fails in multi={true}
When using multi={true}, I had to pass the whole value array in "onChange" event to get all the values.
onChange(value) {
if (this.props.input.onChange) {
this.props.input.onChange(value);
}
}
Here's the last update how to use react-select (1.0.0-rc.2) with redux-form (5.3.4)
SelectInput.js
import React from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
export default (props) => (
<Select
{...props}
value={props.input.value}
onChange={(value) => props.input.onChange(value)}
onBlur={() => props.input.onBlur(props.input.value)}
options={props.options}
/>
);
MyAwesomeComponent.js
import React, {PureComponent} from 'react';
import SelectInput from './SelectInput.js';
class MyAwesomeComponent extends PureComponent {
render() {
const options = [
{'label': 'Germany', 'value': 'DE'},
{'label': 'Russian Federation', 'value': 'RU'},
{'label': 'United States', 'value': 'US'}
];
return (
<Field
name='countries'
options={options}
component={SelectInput}
multi
/>
);
}
I used EclipticWld's example but still have problem with autofocus on selected field
If Im using like @EclipticWld said it works but when input is empty and I dont have any option selected I cant write anything to input so I could filter options. I can only write one chart and thats it. When I select any option then I can filter option and if I delete all already selected options than still the same behavior as described above. Any tip?
As per @EclipticWld's example (thanks!), all works well. I found though that when specifying a different valueKey and labelKey in tandem with an int for the value, the following adjustments needed to be made. Referencing here in case anyone runs into a similar issue.
Given:
const options = [
{'name': 'Germany', 'value': 1},
{'name': 'Russian Federation', 'value': 2},
{'name': 'United States', 'value': 3}
];
Modified:
<Select
{...props}
valueKey='id' labelKey='name'
value={props.input.value}
onChange={(value) => props.input.onChange(value != null ? value.id : null)}
onBlur={() => props.input.onBlur(props.input.value)}
options={options}
/>
With @EclipticWld's example, I always get a value/label key pair instead of the actual value when I submit my form. Is that the norm?
Code snippets:
export const SelectMultiAsync = ({ input, label, meta: { touched, error }, loadOptions }) => (
<FormGroup controlId={label}>
<ControlLabel>{label}</ControlLabel>
<Select.Async
name={input.name}
value={input.value}
multi
loadOptions={loadOptions}
onChange={input.onChange}
onBlur={() => input.onBlur(input.value)}
autoload
/>
</FormGroup>
);
<Field name='examples' label="Examples" component={SelectMultiAsync} validate={validations.required} loadOptions={this.getOptions.bind(this)} />
getOptions(input, callback) {
axios().get(`/cars/select?q=${input}`)
.then(response => response.data)
.then(data => callback(null, {
options: data.map(car => ({ value: car.external_id, label: `${car.plate} - ${car.make.name} ${car.model.name} ${car.version.name} ${car.manufacturing_year}/${car.model_year}`})),
complete: true
}))
}
Form submission values:
examples: [
{
value: 712792,
label: "example1"
},
{
value: 670851,
label: "example2"
},
{
value: 711284,
label: "example3"
},
{
value: 691350,
label: "example4"
}
]
@ultimagriever Hola, you just need to set it correctly, "input.value.value"
onBlur={() => input.onBlur(input.value.value)}
It is an object, so just read out the key you are interested as value to your field.
Why it's doesn't work?

"react-select": "^1.0.0-rc.3",
"redux-form": "^6.6.3"
What am I doing wrong? The value of select doesn't change :(
Sorry, problem from Immutable.js. Solution here http://redux-form.com/6.2.0/examples/immutable/
This is still buggy for async, and I think mostly on the react-select side. When the component is blurred while searching, it doesn't re-render with the original value once the search is complete. Because the value hasn't changed, redux-form doesn't think it needs to be updated, but because it's controlling re-renders at this point, react-select doesn't know that the component hasn't updated with the new value. This can leave the input valid with a chosen value in the store/form but with no value visible. forceUpdate can solve this but there's no reliable place to put it and that's a bad direction anyhow.
@eduardoinnorway @ultimagriever The solution isn't quite so simple as that as you could be dealing with arrays/null values. Here's a more complete solution:
onBlur={() => {
let value= null;
if (Array.isArray(input.value)) {
value = input.value.map((value) => value.value);
}
else if (value != null) {
value = input.value.value;
}
input.onBlur(value);
}
@dtipson from what I can tell, react-select is intentionally filtering out the selected options, and then trying to use the controlled value from redux-form (input.value) to render the selections. However in this case, that controlled value is array of the selected values only rather than of objects w/both the value & label, hence without the labels it has nothing to render. I got around this by adding some state to my redux-form component to handle controlling the component, while redux-form just receives the changes to the value:
<FormField label={label} error={touched && error}>
<Select.Async
value={this.state.selected}
onChange={selected => {
this.setState({ selected })
input.onChange(selected.map(s => s.value))
}}
multi
loadOptions={this.props.loadOptions}
/>
</FormField>
FYI, on the latest react-select (1.0.0-rc.10), there's a prop available called onBlurResetsInput, which is true by default, but can be set to false.
I was using the workarounds mentioned here (which is still a struggle if you allow an array of values) till I stumbled on that prop.
A good solution from @EclipticWld. Depending on your case no need to pass onChange and input.value prop. It works out of the box with a {...props.input}. One thing that you really need is passing onBlur={() => props.input.onBlur(value) implicitly and this will not drop a value of the field on blur.
@RuslanYurchenko owned!
I dont know if this will help anyone but I made react-select v2 worked with redux-form v7
export default class CustomSelect extends Component {
render(){
const { value, options, input} = this.props;
return(
<CreatableSelect
value={value}
onChange={event => input.onChange(event) }
isMulti
closeMenuOnSelect={false}
options = {options}
styles={customStyles}
/>
)
}
}
and in my form component
<div>
<label>Tags</label>
<Field component={CustomSelect} name="tags" options={this.tagsOptions} />
</div>
My experience with react-select v2 and redux-form v7 is that you need to avoid redux-form's onBlur method being passed into react-select.
You can omit it by not spreading the input object into react-select, instead providing what you need, such as the onChange method:
<Select
onChange={(option) => this.props.input.onChange(option.value)}
/>
or you can override it: (notice the order of the props)
<Select
{...this.props.input}
onBlur={this.CustomHandleOnBlur}
/>
hope that helps.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Here's the last update how to use react-select (1.0.0-rc.2) with redux-form (5.3.4)
SelectInput.js
MyAwesomeComponent.js