Flexible Forms in React-Native

Hello 👋

We built an app to simplify care professionals’ life.

Wellbeing Monitoring

Context

Multi-pages form

Similar screens

Frontend Validation

Using Redux? 🤔

Our solution

createStackNavigator({
  Home: HomeScreen,
  ProfilePage: ProfilePageScreen,
  // ...
});
withFormik({
  mapPropsToValues: () => ({ name: '' }),

  // Custom sync validation
  validate: values => {
    const errors = {};

    if (!values.name) {
      errors.name = 'Required';
    }

    return errors;
  },

  handleSubmit: (values, { setSubmitting }) => {
    setTimeout(() => {
      alert(JSON.stringify(values, null, 2));
      setSubmitting(false);
    }, 1000);
  },

  displayName: 'BasicForm',
})(MyForm);

withFormik

createStackNavigator

MoodSelection

MoodNote

ItemSelectionScreen

NoteTakingScreen

Each form is a nested navigator

What Formik handles: Validation

setFieldValue
validate()
errors = { ... }
isValid = false

What Formik handles: SUBMISSION

handleSubmit()
dispatch()
axios.post()
isSubmitting = true

WHat formik handles: FORM INIT

mapPropsToValues()
values = { ... }

How to provide FORM HANDLERS to pages?

// connectToFormik

export default (formikConfig) => (FormNavigator) => {
  class FormikNavigator extends Component {
    static router = FormNavigator.router;

    render() {
      const { navigation, ...otherProps } = this.props;

      return (
        <FormNavigator
          navigation={navigation}
          screenProps={{ ...otherProps }}
        />
      );
    }
  }

  return connect(mapStateToProps)(
    withFormik(formikConfig)(FormikNavigator),
  );
};

HOW TO PROVIDE FORM HANDLERS TO PAGES?

ScreenProps

Flexible templates decoupled from formik

Flexible templates decoupled from Formik

import ItemSelectionScreen from '../_templates/ItemSelectionScreen';
import SelectionItem from '../_templates/SelectionItem';

  render() {
    const { screenProps: { values } } = this.props;
    return (
      <ItemSelectionScreen
        title="What mood were they in?"
        description={description}
        onItemSelected={this.onItemSelected}
      >
        {[Mood.happy, Mood.okay, Mood.sad, Mood.bored].map(mood => (
          <SelectionItem
            key={mood}
            label={_.capitalize(mood)}
            selected={values.mood === mood}
          />
        ))}
      </ItemSelectionScreen>
    );
  }
  onItemSelected = (key) => {
    this.props.screenProps.setFieldValue('mood', key);
    this.props.navigation.navigate('NoteTaking');
  };

Flexible templates decoupled from Formik

Flexible templates decoupled from Formik

// MoodNote
render() {
    return (
      <NoteTakingScreen
        value={this.props.screenProps.values.note}
        buttonTitle="Add mood to report"
        onTextChange={this.onTextChange}
        onComplete={this.onComplete}
        required={this.props.screenProps.values.mood === 'sad'}
      />
    );
}
onTextChange = (text: string) => {
  this.props.screenProps.setFieldValue('note', text);
};
  
onComplete = () => {
  this.props.screenProps.submitForm();
};

Advantages

  • 🔢 Insert/update/delete of pages is super easy
     
  • ⚡️Making broad changes is fast thanks to templates
     
  • 👌Submission & Validation easy to test

Thank you

👨‍💻 Come work with us

🚀 We're growing fast! 

CODE ADDENDUM

NAvigator within navigator

🤔

🤔

NAvigator within navigator

const AppNavigation = createStackNavigator(
  {
    // Home: HomeScreen,
    // Visit: VisitScreen,
    // ...
    MoodForm: {
      screen: MoodFormNavigator,
      navigationOptions,
    },
    FoodIntakeForm: {
      screen: FoodIntakeFormNavigator,
      navigationOptions,
    },
    WeightForm: {
      screen: WeightFormNavigator,
      navigationOptions,
    },
    // ...
  }
);
const navigationOptions = () => ({ header: null });

Avoid this with:

Made with Slides.com