Home >Web Front-end >JS Tutorial >Cascading form React Native Improved

Cascading form React Native Improved

Barbara Streisand
Barbara StreisandOriginal
2024-12-06 01:02:11483browse

I want to share my 3 approaches of handling cascading form fields.

  1. First one is general common approach, using state variables.
  2. Second is to use ordinary variables and one boolean state variable to trigger the state effect (refresh page).
  3. Third is, dynamic form fields with ordinary variables.

First Approach, using state variables

Here in this post we see the second approach, using ordinary variables to handle cascading form fields based on country, state, city data.

Packages

react-native-element-dropdown
react-native-paper

we are using react-native-element-dropdown for drop down fields

Base Page

Cascading form React Native Improved

import React, { useState, useEffect } from "react";
import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
import { Dropdown } from "react-native-element-dropdown";

export default function App() {
  return (
    <View>



<p>ZDropDown is a custom component. </p>

<h3>
  
  
  Sample data
</h3>



<pre class="brush:php;toolbar:false">const listCountry = [
  { countryId: "1", name: "india" },
  { countryId: "2", name: "uk" },
  { countryId: "3", name: "canada" },
  { countryId: "4", name: "us" },
];

const listSate = [
  { stateId: "1", countryId: "1", name: "state1_india" },
  { stateId: "4", countryId: "2", name: "state1_uk" },
  { stateId: "7", countryId: "3", name: "state1_canada" },
  { stateId: "10", countryId: "4", name: "state1_us" },
];

const listCity = [
  {
    cityId: "1",
    stateId: "1",
    countryId: "1",
    name: "city1_state1_country1",
  },
   {
    cityId: "6",
    stateId: "2",
    countryId: "1",
    name: "city6_state2_country1",
  },
  {
    cityId: "7",
    stateId: "3",
    countryId: "1",
    name: "city7_state3_country1",
  }, 
  {
    cityId: "23",
    stateId: "8",
    countryId: "3",
    name: "city23_state8_country3",
  }, 
  {
    cityId: "30",
    stateId: "10",
    countryId: "4",
    name: "city30_state10_country4",
  }, 
  {
    cityId: "35",
    stateId: "12",
    countryId: "4",
    name: "city35_state12_country4",
  },
  {
    cityId: "36",
    stateId: "12",
    countryId: "4",
    name: "city36_state12_country4",
  },
];

Form Variables

In the first approach we used 4 state variables but here we use 4 ordinary variables (3 for dropdown, 1 for focus field) and a state variable which is used to switch and trigger the state effect (refresh page).

var country = {
  list: [],
  selectedCountry: {},
  selectedValue: null,
};

var state = {
  list: [],
  selectedState: {},
  selectedValue: null,
};

var city = {
  list: [],
  selectedCity: {},
  selectedValue: null,
};

var focusField = '';

export default function App() {
 const [refreshPage, setRefreshPage] = useState(false);

  return (
    <View>



<p>Focus and Blur events get triggered more than onChange event so it is better to maintain a separate variable to represent the focus field and avoid data mess up situations. </p>

<h3>
  
  
  Load Country
</h3>

<p>Load country dropdown from the sample data. (you can use api call)<br>
</p>

<pre class="brush:php;toolbar:false">export default function App() {
. . .
  const loadCountry = () => {
    // load data from api call
    country.list = [...listCountry];
    // switching value will refresh the ui
    setRefreshPage(!refreshPage);
  };

  useEffect(() => {
    loadCountry();
  }, []);

return (
. . .
)

Focus / Blur

We're using a function to set the focus field and refresh the page by switching the state variable(refreshPage)

  const changeFocusField = (fld = '') => {
    focusField = fld;
    setRefreshPage(!refreshPage);
  };
        <Text>Country</Text>
        <ZDropDown
          . . .
          isFocus={focusField === 'country'}
          onFocus={() => changeFocusField('country')}
          onBlur={() => changeFocusField('')}
          onChange={null}
        />
        <Text>State</Text>
        <ZDropDown
        . . .
          isFocus={focusField === 'state'}
          onFocus={() => changeFocusField('state')}
          onBlur={() => changeFocusField('')}
          onChange={null}
        />
        <Text>City</Text>
        <ZDropDown        
        . . .
          isFocus={focusField === 'city'}
          onFocus={() => changeFocusField('city')}
          onBlur={() => changeFocusField('')}
          onChange={null}       
        />

Cascading form React Native Improved

We are half way done now.

Load State STATE

On country selected, we need to load the respective states STATES based on the country selection.

Update country field, focus off country and load STATES based on country.

  <Text>Country</Text>
  <ZDropDown
    . . .
    onChange={(item) => {
      country.selectedCountry = item;
      country.selectedValue = item.countryId;
      focusField = '';
      loadState();
    }}
  />

Did you see the difference in the first approach? Previously there were 3 state variables updated but here only one state variable gets updated.

When country changed, both states and cities will be changed. So before setting up the new value we need to clear the existing data.

 const loadState = async () => {
   state = { list: [], selectedState: {}, selectedValue: null };
   city = { list: [], selectedCity: {}, selectedValue: null };
   const arr = listSate.filter(
     (ele) => ele.countryId === country.selectedValue
   );
   if (arr.length) {
     state.list = arr;
   }
   refreshPage(!refreshPage);
 };

Cascading form React Native Improved

Load City

And load city field based on country and state.

    <Text>State</Text>
    <ZDropDown
      . . .
      onChange={(item) => {
        state.selectedValue = item.stateId;
        state.selectedState = item;
        changeFocusField('');
        loadCity();
      }}
     />
  const loadCity = async () => {
    city = { list: [], selectedCity: {}, selectedValue: null };
    const arr = listCity.filter((ele) => ele.stateId === state.selectedValue);
    if (arr.length) city.list = arr;
    setRefreshPage(!refreshPage);
  };

Cascading form React Native Improved

All set, the form fields are working properly now.

Cascading form React Native Improved

2 more additional features, one is resetting the page and the other one is show warning.

Reset page

Form variables and focus variable should be cleared.

. . .
  const resetForm = () => {
    country = {list: [...listCountry],selectedCountry: {}, selectedValue: null};
    state = { list: [], selectedState: {}, selectedValue: null };
    city = { list: [], selectedCity: {}, selectedValue: null };
    focusField = '';
    setRefreshPage(!refreshPage);
  };
. . .

  <TouchableOpacity onPress={() => resetForm()}>



<h3>
  
  
  Warning
</h3>

<p>We have to show a warning msg if the parent field value is null. For that we are using SnackBar component from paper.<br>
</p>

<pre class="brush:php;toolbar:false">import { Snackbar } from "react-native-paper";
. . .
var snackMsg = '';
export default function App() {
  . . .
  const [visible, setVisible] = useState(false);

  const onToggleSnackBar = () => setVisible(!visible);
  const onDismissSnackBar = () => setVisible(false);
  . . .

  return (
    <View>



<p>We moved snackMsg to ordinary variable from state variable.</p>

<p>Since State and City fields have parent field, they have to be validated.<br>
</p>

<pre class="brush:php;toolbar:false">        <Text>State</Text>
        <ZDropDown          
          onFocus={() => {
            focusField('state');
            if (!country.selectedValue) {
              snackMsg = 'Select country';
              onToggleSnackBar();
              changeFocusField('country');
            }
          }}
          . . .
        />
        <Text>City</Text>
        <ZDropDown          
          onFocus={() => {
            focusField('city');
            if (!country.selectedValue) {
              snackMsg = 'Select country';
              onToggleSnackBar();
              changeFocusField('country');
            } else if (!state.selectedValue) {
              snackMsg = 'Select state';
              onToggleSnackBar();
              changeFocusField('state');
            }
          }}
          . . .
        />

Cascading form React Native Improved

Done.

Thank you.

Full code reference here

The above is the detailed content of Cascading form React Native Improved. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn