简体   繁体   中英

Using delete() to remove object from array, and render the objects name in a TextField

I have a component which facilitates entering a data object to an array of objects via submitting the data into a TextField. Upon entering an ingredient, an AddIcon and RemoveIcon will show up on either side of the TextField so you can add or remove ingredients as needed. Entering the data works, and upon entering the data each object is given an id which is associated with the it's id in the array. Adding everything works, however, upon removal of an item I find that the incorrect values are displayed in the TextFields. I'm sure the issue has something to do with how I'm rendering the value of the TextField, but I feel like I need a new pair of eyes on the problem. I've attempted to use both delete() and array.splice(). Here's the code

function MinusButton({ props }) {
  const { 
    id, 
    inputs, 
    setInputs,
    spiritObject,
    setSpiritObject,
    ingredientsArray,
    setIngredientsArray
  } = props;
  
  const removeInput = (e, id) => {
    const tmpInput = [...inputs]
    delete(tmpInput[id])            // this removes the correct object from the array but obviously fails eventually since it doesn't reindex
    // tmpInput.splice(id, 1)       // this technically works as well, but rendering the values does not
    setInputs(tmpInput);
  }

  return (
    <div>
      {
        inputs.length > 1 ?
          <IconButton
            id={id}
            color="primary"
            onClick={(e) => removeInput(e, id)}
          >
            <RemoveIcon fontSize="large"/>
          </IconButton>
        : false
      }
    </div>
  );
}

function PlusButton({ props }) {
  const { 
    id, 
    inputs, 
    setInputs, 
    assignId,
    spiritObject, 
    setSpiritObject, 
    ingredientsArray, 
    setIngredientsArray 
  } = props;

  const addIngredientToArray = () => {
    inputs[id] = { id: id, ...spiritObject}
    setIngredientsArray([...ingredientsArray, inputs[id]])
    setInputs([...inputs, {}])
    setSpiritObject({})
  }

  return (
    <div>
      {
        inputs.length === id+1 ? 
          <IconButton
            color="primary"
            onClick={() => addIngredientToArray()}
          >
            <AddBoxIcon fontSize="large"/>
          </IconButton>
        : false
      }
    </div>
  )
}
  
export default function Ingredients() {
  const classes = useStyles();
  const cocktail = useCocktail();
  const { register, handleSubmit } = useForm();
  const [spiritObject, setSpiritObject] = useState({});
  const [ingredientsArray, setIngredientsArray] = useState([]);
  const [inputs, setInputs] = useState([{}]);

  const onSubmit = () => {
    cocktail.addIngredients(ingredientsArray)
  }

  const onChangeInput = (e) => {
    setSpiritObject({...spiritObject, [e.target.name]: e.target.value})
  }

  return (
    <form 
      noValidate 
      className={classes.formContainer}
      id='ingredients'
      name='ingredients'
      onSubmit={handleSubmit(onSubmit)} 
    >
      {
        inputs.map((input, id) => { 
          const inputProps = { 
            id, 
            inputs, 
            setInputs, 
            spiritObject, 
            setSpiritObject, 
            ingredientsArray, 
            setIngredientsArray 
          }

          return (
            <div>
              <Grid container alignContent="center" alignItems="center">
                <MinusButton props={inputProps} />
                <TextField 
                  {...register('name')}
                  id={id}
                  label='Ingredient'
                  value={inputs[id].name}
                  variant='outlined'
                  margin='normal'
                  InputProps={{className: classes.input}}
                  onChange={(e) => onChangeInput(e)}
                />
                <FormControl variant="outlined" className={classes.formControl}>
                  <Select 
                    {...register('type')}
                    defaultValue="" 
                    id="spiritType"
                    onChange={(e) => onChangeInput(e)}
                  >
                    <ListSubheader>Ingredient Type</ListSubheader>
                    {
                      types.map((type, id) => {
                        return <MenuItem key={id} value={type}>{type}</MenuItem>
                      })
                    }
                  </Select>
                </FormControl>
                <PlusButton props={inputProps} />
              </Grid>
            </div>
          )
        })
      }
    </form>
  );
}

I'm sure the solution is obvious, but I cannot see it. Thank you for reading.

delete is for fields in objects. To remove an entry from an array use filter() .

const tmpInput = [...inputs].filter(element => element.id !== id);

Try to control all your input state into the parent component. handles functions should be side-by-side with your state. Something like this:

import React, { useState } from "react";
import DeleteForeverIcon from "@material-ui/icons/DeleteForever";
import AddBoxIcon from "@material-ui/icons/AddBox";
import { v4 as uuidv4 } from "uuid";

const RemoveButton = ({ onClick }) => (
  <DeleteForeverIcon
    fontSize="large"
    onClick={onClick}
    style={{ cursor: "pointer" }}
  />
);
const AddButton = ({ onClick }) => (
  <AddBoxIcon
    fontSize="large"
    onClick={onClick}
    style={{ cursor: "pointer" }}
  />
);

const InputField = ({ id, onClick }) => {
  return (
    <div>
      <input id={id} />
      <RemoveButton onClick={onClick} />
    </div>
  );
};

const App = () => {
  const [inputs, setInputs] = useState([]);

  const handleRemoveInput = (id) => {
    console.log(id);
    console.log(inputs.findIndex((input) => input.id === id));
    setInputs(inputs.filter((input) => input.id !== id));
  };
  const handleAddInput = () => {
    console.log("asd");
    setInputs([...inputs, { id: uuidv4() }]);
  };

  return (
    <div>
      <AddButton onClick={handleAddInput} />
      {inputs.map(({ id }) => {
        return (
          <InputField id={id} key={id} onClick={() => handleRemoveInput(id)} />
        );
      })}
    </div>
  );
};

export default App;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM