Custom Controls
Sometimes you want to use 3rd-party component libraries, such as Material-UI, React Bootstrap, or better yet, creating your own custom components. It is straightforward to map RRF's actions to event handlers on any kind of custom component:
// ...
import { actions } from 'react-redux-form';
// existing custom component
import CustomInput from '../path/to/custom-input-component';
// wrapper component
// (should be connected to redux store)
class MyCustomInput extends React.Component {
render() {
const { model, dispatch } = this.props;
return (
<CustomInput
onCustomChange={e => dispatch(actions.change(model, e))}
/>
);
}
}
// ...
// Usage:
<MyCustomInput model="user.name" />
However, this can get a bit tedious, especially for complex controls. Thankfully, there's an easier way.
Standard Custom Controls with <Control>
With the <Control>
component, a custom component can be passed into the component={...}
prop, and standard control props and event handlers (such as onChange
, onBlur
, onFocus
, value
, etc.) will be mapped as expected:
import { Control } from 'react-redux-form';
const MyTextInput = (props) => <input className="my-input" {...props} />;
// usage inside render():
<Control
model="user.firstName"
component={MyTextInput}
/>
The mapping standard props to custom controls can be specified by the type of <Control>
component you are using:
// custom radio button
<Control.radio
model="user.gender"
component={MyRadio}
value="F"
/>
// custom checkbox
<Control.checkbox
model="user.active"
component={MyCheckbox}
/>
// ... etc.
By default, any props on <Control>
that are not part of the Control.propTypes
will be passed down to the custom component. To prevent naming collisions or for more predictable prop-passing behavior, you can also specify the props in the controlProps={...}
prop:
<Control.checkbox
model="user.active"
component={MyCheckbox}
label="Is user active?" // will be passed to MyCheckbox
/>
<Control.checkbox
model="user.active"
component={MyCheckbox}
controlProps={{
label: 'Is user active?', // will also be passed to MyCheckbox
}}
/>
Special Custom Controls with <Control.custom>
If you do not want any standard property mappings (such as onChange
, onBlur
, etc.) passed down to your custom control component, use <Control.custom>
and define your own mappings:
<Control.custom
component={SpecialCustomText}
mapProps={{
onTextChange: (props) => props.onChange,
onLoseFocus: (props) => props.onBlur,
// etc.
}}
/>
Model and View Values
One important thing to keep in mind is that there is no single value
for a <Control>
; rather, there are two types of values (that are equivalent, more often than not):
modelValue
- the exact value of the model in the store's stateviewValue
- the displayed value of the model in the component's state
For example, if a text control has updateOn="blur"
, its viewValue
will represent what is being typed in the input, whereas the modelValue
will represent the persisted value, once the input is blurred.
Because of this, you will want to map the viewValue
to a custom control's value
if you wish to externally update the value:
const CustomInput = (props) => (
<div className="custom-input">
<input type="text" {...props} />
</div>
);
const CustomInputControl = (props) => (
<Control
component={CustomInput}
mapProps={{
value: (props) => props.viewValue,
}}
{...props}
/>
);
Alternatively, you can just assign existing mapped props to your custom control:
// the prop mapping of Control.text is used below:
const CustomInputControl = (props) => (
<Control.text component={CustomInput} />
);
Advanced Custom Controls
Some custom controls won't have prop keys that match up exactly with the standard event handler props, such as onChangeText
in React Native's <TextInput>
component corresponding to onChange
. You can specify a prop mapping in the mapProps={{...}}
prop to specify the mapping:
<Control
model="..."
component={DatePickerIOS}
mapProps={{
date: (props) => props.modelValue,
onDateChange: (props) => props.onChange,
}}
/>
If mapProps
is an object, the key corresponds to the custom control's prop key, and the value is a function that takes in the standard props
applied to <Control>
and returns the prop value that the custom prop should map to.
<Control
model="..."
component={DatePickerIOS}
mapProps={ ({modelValue, onChange}) => {
return {
date: modelValue,
onDateChange: onChange,
};
}}
/>
If mapProps
is a function, it is applied to the standard props
, and its return value is used as custom control's props.