From version 1.0, React Redux Form provides mapped <Control>
components for all React Native iOS form controls. To use RRF in React Native, import from react-redux-form/native
:
import React, { View } from 'react-native';
import { Control } from 'react-redux-form/native';
// assuming your store is defined and
// your App is wrapped in a <Provider store={store}>
// from react-redux...
class App extends React.Component {
render() {
return (
<View>
<Control.TextInput model="user.name" />
</View>
);
}
}
// no need to connect!
export default App;
The following React Native iOS and Android form controls are available:
<Control.MapView>
<Control.Picker>
<Control.Switch>
<Control.TextInput>
<Control.Slider>
(note:SliderIOS
is deprecated.)<Control.DatePickerIOS>
<Control.SegmentedControlIOS>
<Control.SegmentedControlAndroid>
- Control.DatePickerAndroid (note: this is a function wrapper around
DatePickerAndroid
, and not a component.)
See below for examples.
The model
prop is required for these controls to work with React Redux Form.
For most controls, the original onFocus
and onBlur
props are mapped to:
onResponderGrant
foronFocus
onResponderRelease
foronBlur
The use of updateOn="blur"
will work as expected for the controls, and is set by default on <Control.MapView>
for performance reasons.
Important: The use of <Field>
in RRF Native is no longer necessary, and is deprecated. <Control>
provides a much cleaner, succinct solution without superfluous React warnings about prop types.
A simple wrapper around DatePickerAndroid
added to give Android feature parity with iOS.
Example usage:
export const MyDatePicker = Control.DatePickerAndroid({
date: new Date(),
mode: 'calendar',
});
try {
const { dismissed, year, month, day } = await MyDatePicker.open();
if (!dismissed) {
const date = `${day}/${month}/${year}`
dispatch(setChosenDate({ date }));
}
} catch (err) {
console.log('Uh oh, spaghetti-o...');
}
Full list of DatePickerAndroid arguments
This component wraps react-native-segmented-control-tab
, full props reference available here.
By default, the <Form>
component is rendered as a <View>
. It handles validity as expected, as well as partial models for child <Control>
components, but it does not have an onSubmit
mechanism.
import { Form, Control } from 'react-redux-form/native';
// render...
<Form model="user" onSubmit={/* ... */}>
<Control.TextInput model=".firstName" />
<Control.TextInput model=".lastName" />
</Form>
To submit a React Native form programmatically:
- Ensure that the
<Form model="foo">
component has anonSubmit={(values) => ...}
callback. - Dispatch a submit action for the form's model (and no other arguments):
dispatch(actions.submit('foo'))
<Form model="user" onSubmit={(vals) => console.log(vals)}>
<Control.TextInput model=".firstName" />
<Control.TextInput model=".lastName" />
<Button onPress={() => dispatch(actions.submit('user'))} />
</Form>
By default, the <Errors>
component will render:
- the wrapper component as a
<View>
- and each error component as
<Text>
.
Of course, you can override this by specifying the component in the wrapper={...}
and component={...}
props of <Errors />
.
Simply import Picker
from react-native
, and pass the Picker.Item
s in as children.
import React, { Picker } from 'react-native';
import { Form, Control } from 'react-redux-form/native';
class Form extends React.Component {
render() {
return (
<Form model="user">
<Control.Picker model=".gender">
<Picker.Item label="Male" value="male" />
<Picker.Item label="Female" value="female" />
<Picker.Item label="Other" value="other" />
</Control.Picker>
</Form>
);
}
}
export default Form;
To use a third-party form control component select the appropriate Control
type (e.g., Control.TextInput
) and override the component
prop with your custom component. The custom component must resolve to one of the supported React Native form control types. See the supported types here.
import React from 'react-native';
import { Form, Control } from 'react-redux-form/native';
import { Input } from 'native-base';
class Form extends React.Component {
render() {
return (
<Form model="user">
<Control.TextInput
placeholder="Last Name"
model=".last_name"
component={Input}
/>
</Form>
);
}
}
export default Form;
If you are using a non-standard form control that does not implement one of the standard React Native iOS form controls (listed here), you will need to manually redefine mapProps
for the control's event handlers.
Below is an example of a custom Picker
component with mapProps
redefined.
import React from 'react-native';
import { Form, Control } from 'react-redux-form/native';
import { Picker } from 'custom-form-library';
class Form extends React.Component {
render() {
return (
<Form model="user">
<Control
component={Picker}
mapProps={{
onResponderGrant: ({ onFocus }) => onFocus,
onResponderRelease: ({ onBlur }) => onBlur,
selectedValue: ({ modelValue }) => modelValue,
onValueChange: ({ onChange }) => onChange,
onChange: undefined,
}}
model=".relationship"
>
<Picker.Item label="Select relationship" value="select" />
<Picker.Item label="Spouse" value="spouse" />
<Picker.Item label="Child" value="child" />
<Picker.Item label="Sibling" value="sibling" />
<Picker.Item label="Parent" value="parent" />
<Picker.Item label="Grandparent" value="grandparent" />
<Picker.Item label="Other" value="other" />
</Control>
</Form>
);
}
}
export default Form;
Below is an example of a custom Input
component. Note that an additional method is defined to handle coercing inputs to string format.
import React from 'react-native';
import { Form, Control } from 'react-redux-form/native';
import { Input } from 'custom-form-library';
function getTextValue(value) {
if (typeof value === 'string' || typeof value === 'number') {
return `${value}`;
}
return '';
}
class Form extends React.Component {
render() {
return (
<Form model="user">
<Control
placeholder="First Name"
model=".first_name"
component={Input}
validators={{
required: val => val && val.length,
}}
mapProps={{
onResponderGrant: ({ onFocus }) => onFocus,
value: _props => ((! _props.defaultValue &&
! _props.hasOwnProperty('value'))
? getTextValue(_props.viewValue)
: _props.value),
onChangeText: ({ onChange }) => onChange,
onChange: undefined,
onBlur: ({ onBlur, viewValue }) => () => onBlur(viewValue),
onFocus: ({ onFocus }) => onFocus,
}}
/>
</Form>
);
}
}
export default Form;