1

This code adds dynamic input fields using react. Two select dropdowns and one input text. When clicking on add button. the same replica of these 3 input fields is added below the old input block. When I change the value of one selected then it automatically changes other select input values. For example, you select the type of jewelry as a ring then, another type of jwellery also got reflected. I am beginner in react.

        import React,{useState } from 'react'
        import Grid from '@material-ui/core/Grid';
        import TextField from '@material-ui/core/TextField';
        import MenuItem from '@material-ui/core/MenuItem';
        import FormControl from '@material-ui/core/FormControl';
        import InputLabel from '@material-ui/core/InputLabel';
        import Select from '@material-ui/core/Select';
        import { makeStyles } from "@material-ui/core/styles";
        import  Button  from '@material-ui/core/Button';
        const backgroundShape = require('./images/background.svg');

        const useStyles = makeStyles(theme => ({
          root: {
            flexGrow: 1,
            backgroundColor: '#064771',
            overflow: 'hidden',
            background: `url(${backgroundShape}) repeat`,
            backgroundSize: 'cover',
            backgroundPosition: '0 1000px',
            paddingBottom: 500
          },
         
          action_btn:{
            marginTop:'10px',
            marginRight: "5px"
          },

          main_grid:{
            backgroundColor: '#fff',
            alignItems: 'center',
            justifyContent: 'center',
            margin:'auto',
            display: 'flex', 
          }
        }));

        function App() {
          const classes = useStyles();

          //handle mmultiple input
          const [state, setState] = React.useState({
            gold_caratage: "",
            gold_type: ""  
          });
          
        // handle input change
        const handleInputChange = (evt) => {
          const value = evt.target.value;
        setState({
          ...state,
          [evt.target.name]: value 
        });
        };

          //clone form logic
          const [inputList, setInputList] = useState([{ jwellary_type: "", net_gram: "",caratage:"" }]);

          //remove and add btn logic 
         const handleRemoveClick = index => {
          const list = [...inputList];
          list.splice(index, 1);
          setInputList(list);
        };


         
        // handle click event of the Add button
        const handleAddClick = () => {
          setInputList([...inputList, { jwellary_type: "", net_gram: "",caratage:"" }]);
        };

          return (
            <div className={classes.root}>
              <typography guttorbuttom align="center">
                <h1>React Calc</h1>
              </typography>
            
              {inputList.map((x, i) => {
                return (
                  <Grid container className={classes.main_grid} spacing={3}>
                  <Grid item xs={10} sm={2}>
                  <FormControl style={{ minWidth:140 }}>
                    <InputLabel id="demo-simple-select-label">Type Of Jwellary</InputLabel>
                    <Select
                      name="gold_type"
                      value={state.gold_type}
                      onChange={handleInputChange}
                    >
                      <MenuItem value={1}>Ring</MenuItem>
                      <MenuItem value={2}>Chain</MenuItem>
                      <MenuItem value={3}>Other</MenuItem>
                    </Select>
                  </FormControl>
                </Grid>
                <Grid item xs={10} sm={2}>
                  <TextField
                     name="Net Gram"
                    label="Net Gram"
                    type="number" 
                    fullwidth
                  />
                </Grid>
                <Grid item xs={10} sm={2}>
                  <FormControl style={{ minWidth: 120 }}>
                    <InputLabel id="demo-simple-select-label">Caratage</InputLabel>
                    <Select
                       value={state.gold_caratage}
                      onChange={handleInputChange}
                      name="gold_caratage"
                    >
                      <MenuItem value={1}>22</MenuItem>
                      <MenuItem value={2}>23</MenuItem>
                      <MenuItem value={3}>24</MenuItem>
                    </Select>
                  </FormControl>
                </Grid>
                <Grid item xs={10} sm={2}>
                  <Button 
                    variant="contained" 
                    color="secondary" 
                    className={classes.action_btn}
                    onClick={() => handleRemoveClick(i)}>
                    Remove
                   </Button> 
                   <Button 
                      variant="contained" 
                      color="primary" 
                      className={classes.action_btn}
                      onClick={handleAddClick}>
                    Add
                   </Button> 
                </Grid> 
                </Grid>  
                );
              })} 
                

            </div>
          )
        }

        export default App;

1 Answer 1

2

Issue

The main issue here is that you've a single state that is used for all the input values and other than index there is no way to differentiate one set of inputs from the next.

Solution

When adding new input sets to the inputList you will want to assign unique id properties to each set. This serves a couple purposes:

  1. The id can be used as the React key for each mapped input set. This helps with rerendering and reconciliation when input sets are deleted.
  2. You can use the id for updating and deleting state.

There is no need for the separate input state state, the inputList state has all the data necessary.

import { v4 as uuidV4 } from 'uuid';

export default function App() {
  const classes = useStyles();

  //clone form logic
  const [inputList, setInputList] = useState([
    {
      id: uuidV4(), // <-- provide id
      jwellary_type: "",
      net_gram: "",
      caratage: ""
    }
  ]);

  // handle input change
  const handleInputChange = (id) => (evt) => {
    const { value } = evt.target;
    setInputList((list) =>
      list.map((el) =>                 // <-- shallow copy array
        el.id === id                   // <-- match by id
          ? {
              ...el,                   // <-- shallow copy element
              [evt.target.name]: value // <-- update key/value
            }
          : el                         // <-- or return current element
      )
    );
  };

  //remove and add btn logic
  const handleRemoveClick = (id) => {
    // <-- shallow copy array and remove elements with mismatch id
    setInputList((list) => list.filter((el) => el.id !== id));
  };

  // handle click event of the Add button
  const handleAddClick = () => {
    setInputList([
      ...inputList,
      {
        id: uuidV4(), // <-- provide id
        jwellary_type: "",
        net_gram: "",
        caratage: ""
      }
    ]);
  };

  return (
    <div className={classes.root}>
      <typography guttorbuttom align="center">
        <h1>React Calc</h1>
      </typography>

      {inputList.map((x, i) => {
        return (
          <Grid
            key={x.id} // <-- provide id as React key
            container
            className={classes.main_grid}
            spacing={3}
          >
            <Grid item xs={10} sm={2}>
              <FormControl style={{ minWidth: 140 }}>
                <InputLabel id="demo-simple-select-label">
                  Type Of Jwellary
                </InputLabel>
                <Select
                  name="jwellary_type" // <-- name to match property
                  value={x.jwellary_type} // <-- current property
                  onChange={handleInputChange(x.id)} // <-- pass id
                >
                  <MenuItem value={1}>Ring</MenuItem>
                  <MenuItem value={2}>Chain</MenuItem>
                  <MenuItem value={3}>Other</MenuItem>
                </Select>
              </FormControl>
            </Grid>
            <Grid item xs={10} sm={2}>
              <TextField
                name="Net Gram"
                label="Net Gram"
                type="number"
                fullwidth
              />
            </Grid>
            <Grid item xs={10} sm={2}>
              <FormControl style={{ minWidth: 120 }}>
                <InputLabel id="demo-simple-select-label">Caratage</InputLabel>
                <Select
                  value={x.caratage} // <-- current property
                  onChange={handleInputChange(x.id)} // <-- pass id
                  name="caratage" // <-- name to match property
                >
                  <MenuItem value={1}>22</MenuItem>
                  <MenuItem value={2}>23</MenuItem>
                  <MenuItem value={3}>24</MenuItem>
                </Select>
              </FormControl>
            </Grid>
            <Grid item xs={10} sm={2}>
              <Button
                variant="contained"
                color="secondary"
                className={classes.action_btn}
                onClick={() => handleRemoveClick(x.id)} // <-- pass id
              >
                Remove
              </Button>
              <Button
                variant="contained"
                color="primary"
                className={classes.action_btn}
                onClick={handleAddClick}
              >
                Add
              </Button>
            </Grid>
          </Grid>
        );
      })}
    </div>
  );
}

Edit how-should-i-manage-multiple-select-fields-dynamically-added-in-react-js

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much, sir, I will check with this code.
It is working fine sir your logic is amazing, thank you so much...!!!!!!!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.