Frequently Asked Questions
This list will be updated frequently!
How do I combine the reducer created by react-redux-form and combineForms
with other reducers?
Use it along side the other reducers and call combineForms with the second argument set to the reducer key of your choice, deep
in the following example):
const store = createStore(combineReducers({
nav: navReducer, // <== here
foo: fooReducer,
bar: barReducer,
deep: combineForms({
user: initialUserState,
goat: initialGoatState,
}, 'deep'),
}));
How do I add conditional class names based on field state?
Use the mapProps={{...}}
property on <Control>
components to set any props on the control component based on field state, like this:
<Control.text
model="user.firstName"
mapProps={{
className: ({fieldValue}) => fieldValue.focus
? 'focused'
: ''
}}
/>
The props that are provided to each function value in your mapProps
mapping are:
modelValue
fieldValue
onFocus
onBlur
onChange
as well as other additional props:
- all props on the
<Control>
- all props on the
controlProps={{...}}
prop (if any) onKeyPress
viewValue
How do I validate across fields?
Validation across fields becomes a higher form-level concern, which follows Redux's general tree-structure data flow pattern. If you want a reusable group of fields that are validated, you can nest forms as long as you set the form's component="..."
prop to something other than "form"
(because you can't nest forms in HTML). See this issue response for more information. Here's an example:
import { Form, Control } from 'react-redux-form';
const isOver18 = (day, month, year) => { ... };
const BirthDate = ({forModel}) => (
<Form
model={`${forModel}.birth`}
component="div"
validators={{
'': ({day, month, year}) => isOver18(day, month, year),
}}
>
<Control model=".day" placeholder="Day" />
<Control model=".month" placeholder="Month" />
<Control model=".year" placeholder="Year" />
</Form>
);
export default BirthDate;
Also, see the validation guide for more information.
How do I get the component instance? ref={...}
doesn't work.
Use getRef={(node) => ...}
in place of ref
. This is due to the fact that React treats the ref
prop as a "magic" prop that doesn't get propagated down through wrapped components.
You can use getRef
on <Field>
, <Control>
, <Form>
, or <LocalForm>
components.
(since: version 1.3.2)
<Control.text
model="user.name"
getRef={(node) => this.attach(node)}
/>
How do I set up single/multiple-value checkboxes?
For a single checkbox that represents a model's boolean true
or false
value, you can use <Control.checkbox>
as expected:
// if checked, user.hasPets = true, otherwise false.
<Control.checkbox model="user.hasPets" />
For multiple checkboxes that represent multiple possible values for a model, append []
to the control to indicate that it is a multi-value model:
// if dog and cat are checked, model will be:
// user.pets = ['dog', 'cat']
<Control.checkbox model="user.pets[]" value="dog" />
<Control.checkbox model="user.pets[]" value="cat" />
<Control.checkbox model="user.pets[]" value="goat" />
For single or multiple checkboxes that represent boolean keyed values in a model that's an object, use standard dot notation:
// if dog and cat are checked, model will be
// user.pets = { dog: true, cat: true, goat: false }
<Control.checkbox model="user.pets.dog" />
<Control.checkbox model="user.pets.cat" />
<Control.checkbox model="user.pets.goat" />
How do I create a file upload form?
The second argument of the <Form onSubmit={(values, event) => ...}>
prop provides the event emitted when the form was submitted. Adapted from the MDN docs:
class UploadForm extends Component {
onSubmit = (values, event) => {
const formData = new FormData(event.target);
const request = new XMLHttpRequest();
request.open('POST', '/upload', true);
request.onload = function(oEvent) {
if (request.status == 200) {
console.log('Uploaded!');
} else {
console.log('Error uploading.');
}
};
request.send(formData);
event.preventDefault();
}
render() {
return (
<Form
model="user"
encType="multipart/form-data"
onSubmit={this.onSubmit}
>
<Control.file model=".avatar" />
<button>Upload!</button>
</Form>
);
};
}
How do I use HTML5 inputs of other types, such as email and password?
Simply pass the type="email"
or type="password"
, etc. type as a prop to <Control>
:
<Control type="email" />
<Control type="password" />
// also works
<Control.text type="email" />
<Control.text type="password" />
You will also get the native HTML5 constraint validation with these, as if you were using <input type="email">
.
How do I hide native HTML5 validation messages, and still prevent the form from submitting if invalid?
You might think that noValidate
will solve this issue, but according to the W3 spec for noValidate
, it does not prevent a form from being submitted if the form is invalid due to HTML5 constraint validity. RRF follows the spec closely with regard to this behavior.
To solve this, since version 0.14.0, the hideNativeErrors
prop can be used to indicate that you do not want native HTML5 constraint validation messages appearing. This will still retain the behavior that if a control is invalid due to HTML5 validation, the form will fail to submit:
// native errors will NOT show
// <Errors /> will show when touched (or submit button clicked) as expected
<Form model="user" hideNativeErrors>
<Control.text
model=".email"
type="email"
/>
<Errors
model=".email"
messages={{
valueMissing: 'Hey, where is your email?',
typeMismatch: 'Not a valid email!'
}}
show="touched"
/>
<button>Submit!</button>
</Form>
Using hideNativeErrors
is the recommended way to solve this. However, if you want to prevent HTML5 validation messages from showing on individual controls, use the native onInvalid
handler to prevent the native HTML5 validation message from displaying:
<Control.text
model="user.email"
type="email"
onInvalid={e => e.preventDefault()}
/>
With partial models, how do I get the fully resolved model string?
You can always grab the fully resolved model string from the <Control>
-specific props through mapProps
:
<Control.text
model=".firstName"
mapProps={{ model: ({ model }) => model }}
/>
// model will be the fully resolved model,
// e.g., "user.firstName"
This is especially useful for custom components, such as a checkbox wrapped in a label, that need the fully resolved model string.