Create a FormBuilder component in React Native (Part 7)
Vasile Stefirta π²π© βοΈ πΊπΈ
Posted on March 18, 2019
This series contents:
- Part 1: Create a new React Native app
- Part 2: Create a simple Salary Calculator Form
- Part 3: Create custom form input and button components
- Part 4: Work on the
FormBuilder
component - Part 5: Enable/disable form buttons on-the-fly
- Part 6: Create a Sign Up form
- Part 7: Add support for Boolean field type (current)
Part 7: Add support for Boolean field type
Now that we verified that our FormBuilder
worked perfectly fine while creating a new form, let's see how we can add support for a new field type - a Boolean
field in our case.
Create a new FormBooleanInput
component
Let's start by creating a new custom component which will render out a Boolean field for us. We'll call it FormBooleanInput
:
import React from 'react';
import PropTypes from 'prop-types';
import {
View, Switch, Text, StyleSheet,
} from 'react-native';
/**
* A stateless function component which renders a Boolean input (Switch).
*
* @param {obj} props
*/
const FormBooleanInput = (props) => {
const { labelText, ...inputProps } = props;
return (
<View style={styles.switchWrapper}>
<Switch {...inputProps} />
{labelText && <Text style={styles.label}>{labelText}</Text>}
</View>
);
};
FormBooleanInput.propTypes = {
labelText: PropTypes.string,
};
FormBooleanInput.defaultProps = {
labelText: null,
};
const styles = StyleSheet.create({
switchWrapper: {
flex: 1,
marginBottom: 15,
paddingHorizontal: 10,
flexDirection: 'row',
alignItems: 'center',
},
label: {
flex: 1,
color: '#FFF',
marginLeft: 10,
},
});
export default FormBooleanInput;
As you can see it's a pretty basic component which renders out a Switch React Native component along with a label (if provided).
Add a new field to the Sign Up
form
Let's use the Sign Up form we created in our last post and add a new field to it, which hypothetically will allow users to subscribe to a mailing list. The field's "definition" would look like this:
[
{
name: 'subscribe',
label: 'Subscribe me to weekly news from Tech world.',
type: 'boolean',
defaultValue: true,
},
]
You've probably noticed the new defaultValue
field property. We'll use it to allow us having default values for any of our form fields. See the next section for details about how we'll be implementing this logic.
Add support for the boolean
field within the FormBuilder
component
Here we'll need to work on a couple of changes:
- Allow form fields to have predefined default values by using the
defaultValue
field's property. Let's create a helper function which will detect for us what should be the default value for a given field.
/**
* Determine what should be the default value
* for a given field.
*/
getFormFieldDefaultValue = ({ defaultValue, type }) => {
if (defaultValue !== undefined) {
return defaultValue;
}
switch (type) {
case 'boolean':
return false;
default:
return '';
}
};
Now we can make use of this function within our constructor()
like so:
const formFieldNames = formFields.reduce((obj, field) => {
obj[field.name] = this.getFormFieldDefaultValue(field);
return obj;
}, {});
- Update our
hasValidFormData()
helper function to ignoreboolean
field types simply because this type of fields will always have a value (eithertrue
orfalse
). The updated version looks like this:
hasValidFormData = () => {
const formFields = this.getFormFields();
const isFilled = formFields
// filter out Boolean fields because they will always have a value
.filter(field => field.type !== 'boolean')
// check if all remaining fields have been filled out
.every(field => !!this.state[field.name]);
return isFilled;
};
- Update our
hasDirtyFormData()
helper function and use a different approach for detecting if aboolean
field changed its value or not, like so:
hasDirtyFormData = () => {
const formFields = this.getFormFields();
const isDirty = formFields.some((field) => {
switch (field.type) {
case 'boolean':
// because Boolean fields will have a default value,
// we need to check if the current value is not the default one
return this.state[field.name] !== this.getFormFieldDefaultValue(field);
default:
return !!this.state[field.name];
}
});
return isDirty;
};
- Create a new
renderBooleanInput()
helper function which will render out theFormBooleanInput
component for us. The function it's not very different from the existingrenderTextInput()
. Probably the main difference is using onValueChange prop instead of onChangeText.
renderBooleanInput = ({ name, label, inputProps }) => (
<FormBooleanInput
{...inputProps}
value={this.state[name]}
onValueChange={(value) => {
this.setState({ [name]: value });
}}
labelText={label}
key={name}
/>
);
- And lastly, let's update our component's
render()
function and render outboolean
fields (if any were provided).
{formFieldsRows.map((formFieldsRow, i) => (
<View style={styles.row} key={`r-${i}`}>
{formFieldsRow.map((field) => {
switch (field.type) {
case 'boolean':
return this.renderBooleanInput(field);
default:
return this.renderTextInput(field);
}
})}
</View>
))}
That's it! Let's take a look at how the form works at this point:
For a full list of changes, check out this commit on GitHub.
That's it my friends! πππ’ I think we've covered enough content to give you an idea on how to build your own FormBuilder
component from scratch. ποΈ Even though I'm going finish this series here, there are still so many things we can apply to this helper component (e.g. support for optional fields, support for new field types, etc.), but let's consider that as homework for you π¨βπ»π©βπ».
Bonus links π
Here are some good resources I used to get started with React Native:
- https://reactjs.org/docs/getting-started.html (you'll have to understand how React works before diving into React Native)
- https://redux.js.org/basics (optional if you're just getting started with React Native, but when you'll be building more complex apps, you may need to reach out for Redux)
- https://facebook.github.io/react-native/
- http://www.reactnativeexpress.com/
Packages:
- https://reactnavigation.org (use this package when you want to navigate between screens or create some sort of tabbed application. It's very well documented and I had no issues using it.)
- https://github.com/react-native-community (an awesome organization which created a lot of great packages for the community)
- https://github.com/zo0r/react-native-push-notification
- https://github.com/invertase/react-native-firebase
App Icons + Splash Screens setup (that's always a tricky part so the links below definitely helped me):
- https://medium.com/@scottianstewart/react-native-add-app-icons-and-launch-screens-onto-ios-and-android-apps-3bfbc20b7d4c
- https://medium.com/handlebar-labs/how-to-add-a-splash-screen-to-a-react-native-app-ios-and-android-30a3cec835ae
Happy coding! π¨βπ»π©βπ»π
Posted on March 18, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.