【问题标题】:React - How do I remove array item from state?React - 如何从状态中删除数组项?
【发布时间】:2020-08-15 18:03:26
【问题描述】:

在我的 react 应用程序中,我创建了一个名为 Add Product 的页面,其中包含一个名为 Add Variation 的按钮,以允许添加产品的小型、中型、大型变体,但可以'不知道如果用户改变主意,如何从状态中删除小、中或大的变化对象。

以下是问题的摘要:

这是组件现在的样子:

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;

每次点击添加变体,页面都会附加另一个VariationComponent 表单。例如,如果 添加变体 按钮被点击了 3 次,则会产生 3 个带有 3 个附加的 删除变体 按钮的 VariationComponent 表单。不幸的是,我不知道如何告诉 React variations 中 #2 项目的位置来删除它,所以我求助于 .pop() 解决这个问题,这不是我想要的。

当点击Remove Variation按钮时,如何告诉React删除正确的数组项?

【问题讨论】:

  • 一般来说,当你想删除给定索引处的元素时,使用splice 而不是pop。但我真的很难理解你的代码是如何工作的。在几个地方,您引用了似乎未定义的 variations 变量 - 相关数组仅作为 values 状态对象的属性存在。
  • 实际上,不是splice 发生变异(pop 也是如此),您最好使用filter 返回一个新数组,该数组缺少具有所需索引的数组。
  • @RobinZigmond 我很抱歉,第二次看时我意识到我遗漏了我解构状态值并使它们在范围内可用的部分。请再次查看我的更新答案。
  • @RobinZigmond 好的,我在filter 和你在一起,但我将如何在这里使用它?如果我更改按钮并像这样传递i ,则会引发错误。事实上,我一直无法用参数调用处理程序,这就是我卡住的地方。我想过滤但还不能解决如何通过位置。
  • 如果我错了,请纠正我,但您似乎有一个“删除”按钮,可以删除您拥有的三个“变体”中的任何一个。对于将索引映射到您的 removeVariation 函数的每个“变体”可能有一个“删除”按钮似乎更合适,您的 onClick 处理程序可能看起来像 &lt;button onClick={() =&gt; removeVariation(i)}&gt;Remove variation&lt;/button&gt;

标签: javascript node.js reactjs jsx


【解决方案1】:

如果我理解正确,您可以使用 Array.filter() 确定要删除的变体。它返回一个新数组,除了匹配的 numberVal 之外的所有数组。

onClick={e=>removeVariation(e)}

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

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

【讨论】:

  • 您能分享一下您将如何从 onClick 调用它吗?我试过了,但它删除了数组中的所有内容。我仍在使用onClick={removeVariation},但我现在意识到我可以通过这样的位置:onClick={() =&gt; removeVariation(i)} 然后我得到一个TypeError: e.preventDefault is not a function
  • 很难理解为什么你定义handleVariationChange,然后使用handleChange,但无论哪种方式,我认为你要使用的是Array.filter()Array.slice()
  • 这是由于 handleChange 创建了主要项目的名称、类别和照片,但 handleVariationChange 仅填充 variations 数组。变体是位于 products 集合中的主要项目文档上的一个属性,并使用 ObjectId 来引用 variations 集合。这些variations 最终成为mongodb 中variations 集合中的单独文档,我在我的/shop 页面中调用它时.populate("variations")
  • 我更新了我的答案,但基本上,我会将e 传递给onChange,然后您可以使用e.target.namee.target.value 检查属性。这样您就不必手动将每个字符串传递到 onChange 中,因为您已经通过 jsx 属性区分了不同的元素。你明白吗?
  • 我已经成功了!以下是最终奏效的方法:onClick={(e) =&gt; removeVariation(e, variations[i].number)}
【解决方案2】:

感谢@RobinZigmond 和@7iiBob 的回答,我能够通过以下代码解决这个问题:

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

移除变体按钮:

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

请记住,空的变体对象如下所示:

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

n 来自addVariation

    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: ""
        })
    }

衷心感谢您,因为这让我头疼了好几个小时!

【讨论】:

  • 抱歉,我离开了一段时间 - 但很高兴你自己弄清楚了
猜你喜欢
  • 1970-01-01
  • 2016-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-26
相关资源
最近更新 更多