Custom Components
It is straightforward to map React-Redux-Form's actions to event handlers on any kind of custom component. This is the recommended way to handle custom components, as issues may arise when components do not have a .displayName
(this is how React-Redux-Form recognizes components).
import React from 'react';
import { connect } from 'react-redux';
import { actions } from 'react-redux-form';
// existing custom component
import CustomInput from '../path/to/custom-input-component';
// wrapper field
class MyCustomInput extends React.Component {
render() {
let { model, dispatch } = this.props;
return (
<CustomInput
onCustomChange={e => dispatch(actions.change(model, e))}
/>
);
}
}
export default connect(s => s)(CustomField);
// Usage:
<MyCustomInput model="user.name" />
For all other custom and 3rd-party components that properly have a displayName
, custom <Field>
adapters can be created using createFieldClass()
to map standard props to custom props.
Important: The .displayName
component property is minified in production builds. To work around this with createFieldClass()
, map the component name to the component constructor in defaultProps.componentMap
(see below).
createFieldClass(propsMap, [defaultProps])
The createFieldClass()
function accepts two arguments: a component-prop { key: value }
mapping where the:
key
is the component name*, and thevalue
is a function that takes in the existing prop mapping and returns a new prop mapping.
and an optional defaultProps
object, which should include:
- any
defaultProps
you would like to override in<Field>
, .componentMap
, which is a mapping of component names to their constructors, such as:
// second argument to createFieldClass(propsMap, defaultProps)
{
...customDefaultProps,
componentMap: {
TextField: TextField
}
}
* Important: Without the .componentMap
, the key
(component name) relies on the custom component's .displayName
static property, which is minified in production builds. Make sure the component's name is explicitly mapped to its constructor in defaultProps.componentMap
.
For example, the React Native <PickerIOS />
component has an onValueChange
event handler prop and a selectedValue
prop. We want to map these "custom" event handler props to behave like the standard props:
onValueChange
should be mapped toonChange
selectedValue
should be mapped tovalue
This is all done in the component-prop mapping:
import { createFieldClass } from 'react-redux-form';
const NativeField = createFieldClass({
'PickerIOS': (props) => ({
onValueChange: props.onChange,
selectedValue: props.modelValue
})
}, {
componentMap: {
PickerIOS: PickerIOS, // recognize component by constructor
}
});
// in the component's render() method:
<NativeField model="...">
<PickerIOS>
...
</PickerIOS>
</NativeField>
Now, if you know for certain that a custom component has the same property mappings as an existing native (DOM) control, the controls
component-props mapping can be imported for convenience, which contains the following mappings:
"text"
for<input type="text" />
and all other text-based<input />
elements (liketype="color"
, etc.)"textarea"
for<textarea />
"checkbox"
for<input type="checkbox" />
"radio"
for<input type="radio" />
"select"
for<select> ... </select>
For example, in material-ui, the TextField
component has the same event handler props as <input type="text" />
(onChange
, onBlur
, onFocus
, etc.), so mapping is straightforward with controls
:
import { createFieldClass, controls } from 'react-redux-form';
import TextField from 'material-ui/lib/text-field';
const MaterialField = createFieldClass({
'TextField': controls.text
}, {
componentMap: {
TextField: TextField
}
});
// render():
<MaterialField model="...">
<TextField />
</MaterialField>
Note: The defaultProps.componentMap
property is available in version 0.13.6
.