Dynamic Form Fields Based on Selected Category in React Native

I am developing a React Native application where I need to create a form that displays different fields based on the user’s selected category. I am using Formik for form handling and want to conditionally render form fields depending on the category selected from a dropdown.

I have set up a basic form using Formik, and I have a dropdown (or picker) that allows the user to select a category. However, I’m struggling with the logic to conditionally render different sets of form fields based on the selected category.

Here’s a snippet of my current implementation:

`

import React, { useContext, useCallback } from "react";
import { ScrollView } from "react-native";
import { Formik } from "formik";
import InputField from "./InputForm";
import { useNavigation } from "@react-navigation/native";
import { DispatchContext, StateContext } from "../../store";
import SubmitButton from "../Button/SubmitButton";
import FormPicker from "./FormPicker";
import { convertToFormData } from "../../utlis/FormDataUtils";
import FormValidation from "./FormValidation";
import { FormStyles } from "./FormStyles";
import CategoryFormFields from "./CategoryFormFields";
import { Services } from "../../services/DirectoryServices";

const Form = () => {
  const dispatch = useContext(DispatchContext);
  const { user, address } = useContext(StateContext);
  const navigation = useNavigation();

  // Getting userId and initializing form values
  const userId = user?.session?.data?.attributes?.id || "Null";
  const initialValues = {
    country: "",
    state: "",
    name: "",
    description: "",
    address: address,
    contact: "",
    email: "",
    tags: "",
    activities: "",
    pics: [],
    hours: "",
    amenities: "",
    prices: "",
    seat: "",
    details: "",
    language: "",
    profilePic: "",
    expertise: "",
    experience: "",
    availability: "",
    licenses: "",
    certificate: "",
    unit: "",
    user_id: userId,
    category: "",
  };

  // Handling location selection
  const handleLocationSelect = useCallback(
    (selectedAddress) => {
      dispatch({
        type: "UPDATE_LOCATION",
        payload: selectedAddress,
      });
    },
    [dispatch]
  );

  // Submitting the form data
  const onSubmit = useCallback(
    (values, { resetForm }) => {
      try {
        const formData = convertToFormData(values);
        Services("post", null, formData)
          .then((res) => {
            dispatch({
              type: "SNACKBAR_OPEN",
              payload: {
                isNotify: true,
                severity: "success",
                message: "Submission Successful!",
              },
            });
            navigation.goBack();
            resetForm();
          })
          .catch((err) => {
            console.error("Submission Error:", err);
            dispatch({
              type: "SNACKBAR_OPEN",
              payload: {
                isNotify: true,
                severity: "error",
                message: "Submission Failed!",
              },
            });
          });
      } catch (err) {
        console.error("Error during form submission:", err);
      }
    },
    [dispatch, navigation]
  );

  return (
    <Formik
      initialValues={initialValues}
      validationSchema={FormValidation}
      onSubmit={onSubmit}
    >
      {({
        handleChange,
        handleBlur,
        handleSubmit,
        values,
        errors,
        touched,
        setFieldValue,
      }) => (
        <ScrollView style={FormStyles.container}>
          <FormPicker values={values} handleChange={handleChange} />
          <CategoryFormFields
            values={values}
            handleChange={handleChange}
            handleBlur={handleBlur}
            errors={errors}
            touched={touched}
            setFieldValue={setFieldValue}
          />
          {/* Input fields for Name, Contact, Description, and Email */}
          <InputField
            label="Name *"
            placeholder="Enter name"
            onChangeText={handleChange("name")}
            onBlur={handleBlur("name")}
            value={values.name}
            error={errors.name}
            touched={touched.name}
          />
          <InputField
            label="Contact *"
            placeholder="Enter contact"
            onChangeText={handleChange("contact")}
            onBlur={handleBlur("contact")}
            value={values.contact}
            error={errors.contact}
            touched={touched.contact}
          />
          <InputField
            label="Description *"
            placeholder="Enter description"
            onChangeText={handleChange("description")}
            onBlur={handleBlur("description")}
            value={values.description}
            error={errors.description}
            touched={touched.description}
          />
          <InputField
            label="Email *"
            placeholder="Enter email"
            onChangeText={handleChange("email")}
            onBlur={handleBlur("email")}
            value={values.email}
            error={errors.email}
            touched={touched.email}
          />
          {/* Address Input with Location Selection */}
          <InputField
            label="Address *"
            placeholder="Enter address"
            onChangeText={handleChange("address")}
            onBlur={handleBlur("address")}
            value={values.address}
            error={errors.address}
            touched={touched.address}
            onLocationPress={() => {
              navigation.navigate("MapOverview", {
                onSelectLocation: (lat, long, selectedAddress) => {
                  handleLocationSelect(selectedAddress);
                  setFieldValue("address", selectedAddress);
                },
              });
            }}
          />
          <SubmitButton onPress={handleSubmit} />
        </ScrollView>
      )}
    </Formik>
  );
};

export default Form;
import React from "react";
import { Text } from "react-native";
import CategoryPicker from "../CategoryPicker/CategoryPicker";
import InputField from "./InputForm";
import { FormStyles } from "./FormStyles";
import MultipleImageSelector from "../ImagePicker/MultipleImageSelector";
import SingleImageSelector from "../ImagePicker/SingleImageSelector";

const CategoryFormFields = ({
  values,
  handleChange,
  handleBlur,
  errors,
  touched,
  setFieldValue,
}) => {
  return (
    <>
      <CategoryPicker
        values={values}
        handleChange={handleChange}
        error={errors.category}
      />
      {errors.category && (
        <Text style={FormStyles.error}>{errors.category}</Text>
      )}

      {values.category === "HomeStay" && (
        <>
          <InputField
            label="Rate *"
            placeholder="Rate"
            onChangeText={handleChange("rate")}
            onBlur={handleBlur("rate")}
            value={values.rate}
            error={errors.rate}
            touched={touched.rate}
          />
          <InputField
            label="Activities *"
            placeholder="Activities"
            multiline
            onChangeText={handleChange("activities")}
            onBlur={handleBlur("activities")}
            value={values.activities}
            error={errors.activities}
            touched={touched.activities}
          />
          <InputField
            label="Amenities *"
            placeholder="Amenities"
            onChangeText={handleChange("amenities")}
            onBlur={handleBlur("amenities")}
            value={values.amenities}
            error={errors.amenities}
            touched={touched.amenities}
          />
          <MultipleImageSelector
            label="Pics *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("pics", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
        </>
      )}

      {values.category === "CarRental" && (
        <>
          <InputField
            label="Vehicle Detail *"
            placeholder="Details"
            onChangeText={handleChange("details")}
            onBlur={handleBlur("details")}
            value={values.details}
            error={errors.details}
            touched={touched.details}
          />
          <InputField
            label="Seat *"
            placeholder="Seat"
            onChangeText={handleChange("seat")}
            onBlur={handleBlur("seat")}
            value={values.seat}
            error={errors.seat}
            touched={touched.seat}
          />
          <InputField
            label="Rate *"
            placeholder="Rate"
            onChangeText={handleChange("rate")}
            onBlur={handleBlur("rate")}
            value={values.rate}
            error={errors.rate}
            touched={touched.rate}
          />
          <InputField
            label="Unit *"
            placeholder="Unit"
            onChangeText={handleChange("unit")}
            onBlur={handleBlur("unit")}
            value={values.unit}
            error={errors.unit}
            touched={touched.unit}
          />
          <MultipleImageSelector
            label="Pics *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("pics", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
        </>
      )}

      {values.category === "Cafe" && (
        <>
          <InputField
            label="Add Tags *"
            placeholder="Add Tags"
            onChangeText={handleChange("tags")}
            onBlur={handleBlur("tags")}
            value={values.tags}
            error={errors.tags}
            touched={touched.tags}
          />
          <InputField
            label="Prices *"
            placeholder="Prices"
            onChangeText={handleChange("prices")}
            onBlur={handleBlur("prices")}
            value={values.prices}
            error={errors.prices}
            keyboardType="numeric"
            touched={touched.prices}
          />
          <MultipleImageSelector
            label="Pics *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("pics", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
          <InputField
            label="Operational Hours *"
            placeholder="Eg: 09:00 AM - 09:00 PM"
            onChangeText={handleChange("hours")}
            onBlur={handleBlur("hours")}
            value={values.hours}
            error={errors.hours}
            touched={touched.hours}
          />
        </>
      )}

      {values.category === "Restaurant" && (
        <>
          <InputField
            label="Add Tags *"
            placeholder="Add Tags"
            onChangeText={handleChange("tags")}
            onBlur={handleBlur("tags")}
            value={values.tags}
            error={errors.tags}
            touched={touched.tags}
          />
          <InputField
            label="Prices *"
            placeholder="Prices"
            onChangeText={handleChange("prices")}
            onBlur={handleBlur("prices")}
            value={values.prices}
            error={errors.prices}
            keyboardType="numeric"
            touched={touched.prices}
          />
          <MultipleImageSelector
            label="Pics *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("pics", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
          <InputField
            label="Operational Hours *"
            placeholder="Eg: 09:00 AM - 09:00 PM"
            onChangeText={handleChange("hours")}
            onBlur={handleBlur("hours")}
            value={values.hours}
            error={errors.hours}
            touched={touched.hours}
          />
        </>
      )}

      {values.category === "Local Guide" && (
        <>
          <InputField
            label="Language *"
            placeholder="Language"
            onChangeText={handleChange("language")}
            onBlur={handleBlur("language")}
            value={values.language}
            error={errors.language}
            touched={touched.language}
          />
          <InputField
            label="Area of Expertise *"
            placeholder="Expertise"
            onChangeText={handleChange("expertise")}
            onBlur={handleBlur("expertise")}
            value={values.expertise}
            error={errors.expertise}
            touched={touched.expertise}
          />
          <InputField
            label="Experience *"
            placeholder="Experience"
            onChangeText={handleChange("experience")}
            onBlur={handleBlur("experience")}
            value={values.experience}
            error={errors.experience}
            touched={touched.experience}
          />
          <InputField
            label="Availability *"
            placeholder="Availability"
            onChangeText={handleChange("availability")}
            onBlur={handleBlur("availability")}
            value={values.availability}
            error={errors.availability}
            touched={touched.availability}
          />
          <SingleImageSelector
            label="ProfilePic *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("profilePic", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
          <SingleImageSelector
            label="License *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("license", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
          <SingleImageSelector
            label="Certificate *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("certificate", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
        </>
      )}

      {values.category === "Bar" && (
        <>
          <InputField
            label="Add Tags *"
            placeholder="Add Tags"
            onChangeText={handleChange("tags")}
            onBlur={handleBlur("tags")}
            value={values.tags}
            error={errors.tags}
            touched={touched.tags}
          />
          <InputField
            label="Prices *"
            placeholder="Prices"
            onChangeText={handleChange("prices")}
            onBlur={handleBlur("prices")}
            value={values.prices}
            error={errors.prices}
            touched={touched.prices}
          />

          <MultipleImageSelector
            label="Pics *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("pics", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
          <InputField
            label="Operational Hours *"
            placeholder="Eg: 09:00 AM - 09:00 PM"
            onChangeText={handleChange("hours")}
            onBlur={handleBlur("hours")}
            value={values.hours}
            error={errors.hours}
            touched={touched.hours}
          />
        </>
      )}

      {values.category === "Tourist Attraction" && (
        <>
          <InputField
            label="Add Tags *"
            placeholder="Add Tags"
            onChangeText={handleChange("tags")}
            onBlur={handleBlur("tags")}
            value={values.tags}
            error={errors.tags}
            touched={touched.tags}
          />
          <InputField
            label="Prices *"
            placeholder="Prices"
            onChangeText={handleChange("prices")}
            onBlur={handleBlur("prices")}
            value={values.prices}
            error={errors.prices}
            touched={touched.prices}
          />

          <MultipleImageSelector
            label="Pics *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("pics", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
          <InputField
            label="Operational Hours *"
            placeholder="Eg: 09:00 AM - 09:00 PM"
            onChangeText={handleChange("hours")}
            onBlur={handleBlur("hours")}
            value={values.hours}
            error={errors.hours}
            touched={touched.hours}
          />
        </>
      )}

      {values.category === "Others" && (
        <>
          <InputField
            label="Add Tags *"
            placeholder="Add Tags"
            onChangeText={handleChange("tags")}
            onBlur={handleBlur("tags")}
            value={values.tags}
            error={errors.tags}
            touched={touched.tags}
          />
          <InputField
            label="Prices *"
            placeholder="Prices"
            onChangeText={handleChange("prices")}
            onBlur={handleBlur("prices")}
            value={values.prices}
            error={errors.prices}
            touched={touched.prices}
          />

          <MultipleImageSelector
            label="Pics *"
            onImageSelected={(images) => {
              console.log("Selected images:", images);
              setFieldValue("pics", images);
            }}
            value={values.pics.length > 0 ? "Images Selected" : ""}
          />
          <InputField
            label="Operational Hours *"
            placeholder="Eg: 09:00 AM - 09:00 PM"
            onChangeText={handleChange("hours")}
            onBlur={handleBlur("hours")}
            value={values.hours}
            error={errors.hours}
            touched={touched.hours}
          />
        </>
      )}
    </>
  );
};

export default CategoryFormFields;

`

While this works for rendering fields for two categories, I want to ensure the approach is scalable and maintainable, especially if I need to add more categories in the future. Additionally, I’m not sure about the best way to handle form validation with conditionally rendered fields.

Expected Outcome

I would like to know:

The best practices for dynamically rendering form fields based on category selection in React Native.
How to efficiently manage validation for conditionally rendered fields using Formik or any other recommended library.
Any example code or resources that demonstrate a similar implementation.
no action when submitting form.