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 the
  • value 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 to onChange
  • selectedValue should be mapped to value

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 (like type="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.

results matching ""

    No results matching ""