redux-form集成react-select等组件需两次点击展开下拉的问题求助
Oh man, I’ve run into this exact problem before—it’s super frustrating when non-native selects need two clicks to open because of redux-form’s onBlur handling! Let’s break down why this happens and walk through a few solid fixes that keep your onBlur functionality intact.
Why This Happens
The root issue is that redux-form’s Field component attaches an onBlur handler to the input element. When you click the react-select dropdown toggle, the browser first triggers the input’s onBlur (since focus moves away from the input to the dropdown menu element). Redux-form processes this blur event immediately, which interrupts react-select’s dropdown open logic—hence the need for a second click to actually trigger the menu.
Solution 1: Control onBlur with a Container Element (Most Reliable)
Wrap your react-select in a container and only trigger redux-form’s onBlur when the focus leaves the entire container, not just the input. This way, clicking the dropdown (which stays inside the container) won’t trigger the blur.
import React from 'react'; import { Field } from 'redux-form'; import Select from 'react-select'; const ReduxFormSelect = ({ input, meta, ...props }) => { const handleContainerBlur = (e) => { // Only trigger redux-form's blur if focus is leaving the entire container if (!e.currentTarget.contains(e.relatedTarget)) { input.onBlur(e); } }; return ( // Add tabIndex=-1 so the container can receive focus events <div onBlur={handleContainerBlur} tabIndex={-1} style={{ display: 'inline-block' }}> <Select value={input.value} onChange={(selectedOption) => input.onChange(selectedOption)} {...props} /> </div> ); }; // Usage in your form <Field name="account" component={ReduxFormSelect} options={yourAccountOptions} placeholder="Select an account" />
Solution 2: Use react-select’s Built-in Events to Trigger Blur
Instead of relying on the default onBlur, use react-select’s onMenuClose event to trigger redux-form’s blur handler. This way, blur only fires when the dropdown closes, not when you first click to open it.
import React from 'react'; import { Field } from 'redux-form'; import Select from 'react-select'; const ReduxFormSelect = ({ input, meta, ...props }) => { return ( <Select value={input.value} onChange={(selectedOption) => input.onChange(selectedOption)} // Trigger redux-form's blur only when the menu closes onMenuClose={() => input.onBlur()} {...props} /> ); };
Solution 3: Manually Touch the Field (If You Need Blur for Validation)
If your main use for onBlur is to mark the field as "touched" (for validation), you can manually dispatch redux-form’s touch action instead of using the default blur handler.
import React from 'react'; import { Field, touch } from 'redux-form'; import Select from 'react-select'; import { connect } from 'react-redux'; const ReduxFormSelect = ({ input, meta, dispatch, formName, ...props }) => { const handleChange = (selectedOption) => { input.onChange(selectedOption); // Manually mark the field as touched when the user selects an option dispatch(touch(formName, input.name)); }; const handleMenuClose = () => { // Or mark as touched when the menu closes dispatch(touch(formName, input.name)); }; return ( <Select value={input.value} onChange={handleChange} onMenuClose={handleMenuClose} {...props} /> ); }; // Connect to get dispatch and pass your form name export default connect()(ReduxFormSelect); // Usage <Field name="account" component={ReduxFormSelect} formName="yourFormName" options={yourAccountOptions} />
Which Solution Should You Pick?
- Solution 1 is the most robust—it mimics native behavior perfectly and keeps all onBlur functionality intact (like triggering validation when the user clicks outside the field entirely).
- Solution 2 is simpler if you only care about blur triggering when the dropdown closes.
- Solution 3 is ideal if your main goal is field validation via the "touched" state.
内容的提问来源于stack exchange,提问作者Janak Patel

