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.