简体   繁体   中英

React - How do I remove array item from state?

In my react app, I have created a page named Add Product with a button named Add Variation to allow adding small, medium, large variations of a product but can't figure out how to remove the small, medium, or large variation object from the state if user changes their mind.

Here's a summary of the problem: 在此处输入图像描述

Here's what the component looks like now:

const AddProduct = () => {
    const [addVar, setAddVar] = useState(0)
    const [values, setValues] = useState({
        name: "",
        description: "",
        categories: [],
        category: "",
        photo: "",
        loading: false,
        error: "",
        createdProduct: "",
        redirectToProfile: false,
        variations: [],
        formData: ""
    });

    const {
        name,
        description,
        price,
        categories,
        category,
        photo,
        loading,
        error,
        createdProduct,
        redirectToProfile,
        variations,
        formData
    } = values;

    const addVariation = (e) => {
        e.preventDefault()
        setAddVar(addVar + 1)
        let oldV = Array.from(variations); // gets current variations
        let n = oldV.length; // get current array position
        console.log(`Current number of variations is: ${n}`);
        let vPost = [{ 
            number: n,
            vname: "",
            vprice: "",
            vquantity: "",
            vshipping: ""
        }]  
        let newV = oldV.concat(vPost);         
        setValues({
            ...values,
            variations: newV,
            error: ""
        })
    }   

    const handleVariationChange = (name, numberVal) => event => {
        // numberVal is the iteration number
        // name is the variation property which can be vname, vprice, vshipping, vquantity
        // these are tested next in the following if statements
        const value = event.target.value;
        console.log(`numberVal: `, numberVal);
        event.preventDefault()
        let newVariations = Array.from(variations)
                
        if(name === "vname") { 
            newVariations[numberVal].vname = value;
            console.log(`newVariations[numberVal].vname value: `, newVariations)
        }

        if(name === "vprice") { 
            newVariations[numberVal].vprice = value;
            console.log(`newVariations[numberVal].vprice value: `, newVariations)
        }

        if(name === "vshipping") { 
            newVariations[numberVal].vshipping = value;
            console.log(`newVariations[numberVal].vshipping value: `, newVariations)
        }

        if(name === "vquantity") { 
            newVariations[numberVal].vquantity = value;
            console.log(`newVariations[numberVal].vquantity value: `, newVariations)            
        }
        
        setValues({...values, variations: newVariations})
        formData.set("variations", JSON.stringify(newVariations));
    };

    const removeVariation = (e) => {
        e.preventDefault()
        let newVariations = Array.from(variations)
        let popped = newVariations.pop()
        
        setValues({
            ...values,
            variations: newVariations,
            error: ""
        })
        
    }

    const newPostForm = () => (
        <form className="mb-3" onSubmit={clickSubmit}>
            <h4>Main Photo</h4>
            <div className="form-group">
                <label className="btn btn-secondary">
                    <input
                        onChange={handleChange("photo")}
                        type="file"
                        name="photo"
                        accept="image/*"
                    />
                </label>
            </div>
            <div className="form-group">
                <label className="text-muted">Main Product Name</label>
                <input
                    onChange={handleChange("name")}
                    type="text"
                    className="form-control"
                    value={name}
                    placeholder="Add main product name"
                />
            </div>
            <div className="form-group">
                <label className="text-muted">Description</label>
                <textarea
                    onChange={handleChange("description")}
                    className="form-control"
                    value={description}
                    placeholder="Add description"
                />
            </div>         
            <div className="form-group">
                <label className="text-muted">Category</label>
                <select
                    onChange={handleChange("category")}
                    className="form-control"
                >
                    <option>Please select</option>
                    {categories &&
                        categories.map((c, i) => (
                            <option key={i} value={c._id}>
                                {c.name}
                            </option>
                        ))}
                </select>
            </div>
            <div>
                    <button onClick={addVariation}>Add variation</button>
                    </div>
                    {variations ? VariationComponent() : null}
            <br />
            <br />
            <button type="submit" className="btn btn-outline-primary">Create Product</button>
        </form>
    );

return (
        <Layout>
            <div className="row">
                <div className="col-md-8 offset-md-2">
                    {newPostForm()}                    
                </div>
            </div>
        </Layout>
    );
};

export default AddProduct;

Every time Add variation is clicked, another VariationComponent form is appended to the page. For example, if Add variation button was clicked 3 times, it would result in 3 VariationComponent forms with 3 attached Remove variation buttons. Unfortunately, I do not see how to tell React the position of the #2 item in variations to remove it so I resorted to solving this with .pop() , which is not what I want.

How can I tell React to remove the right array item when Remove variation button is clicked?

If I understand correctly, you can use Arrray.filter() determine which variation to remove. It returns a new array with all but the matching numberVal.

onClick={e=>removeVariation(e)}

const removeVariation = e => {
  e.preventDefault();

  setValues({
    ...values,
    variations: variations.filter(item => item.name !== e.target.value),
    error: ''
  });
};

Thanks to @RobinZigmond's and @7iiBob's answers, I was able to solve this by this code:

    const removeVariation = (e, num) => {
        e.preventDefault();
      
        setValues({
          ...values,
          variations: variations.filter(item => item.number !== num),
          error: ''
        });
      };

Remove variation button:

<button onClick={(e) => removeVariation(e, variations[i].number)} className="btn-danger">
    {`Remove Variation`}
</button>

Keep in mind the empty variation object looks like this:

        { 
            number: n,
            vname: "",
            vprice: "",
            vquantity: "",
            vshipping: ""
        }

and n is coming from addVariation here:

    const addVariation = (e) => {
        e.preventDefault()
        setAddVar(addVar + 1)
        let oldV = Array.from(variations); // gets current variations
        let n = oldV.length; // get current array position
        console.log(`Current number of variations is: ${n}`);
        let vPost = [{ 
            number: n,
            vname: "",
            vprice: "",
            vquantity: "",
            vshipping: ""
        }]  
        let newV = oldV.concat(vPost);         
        setValues({
            ...values,
            variations: newV,
            error: ""
        })
    }

Wholehearted thank you as this cost me hours of headache!

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