在 ReactJS 中删除项目,使用 useState 和 useContext

Posted

技术标签:

【中文标题】在 ReactJS 中删除项目,使用 useState 和 useContext【英文标题】:Deleting items in ReactJS, using useState and useContext 【发布时间】:2021-06-09 03:33:12 【问题描述】:

作为一个对编程上瘾的新人,我被一个列出项目的简单应用程序所困。添加项目,就OK了。但至于删除一项,我就是想不通如何实现这个功能。现在点击一个项目,整个项目数组被删除。我曾尝试将 deleteItem 函数放在其他文件中,但似乎混淆了引用。

ItemContext.js:

import React,  useState, createContext  from 'react';
import  v1 as uuidv1  from 'uuid';
export const ItemContext = createContext();

export const ItemProvider = (props) => 
  const [items, setItems] = useState([
    
      name: "Red Beans",
      amount: 23,
      id: uuidv1()
    ,
    
      name: "Nuts for Bunnies",
      amount: 33,
      id: uuidv1()
    ,
    
      name: "Chopped Tomatoes",
      amount: 2,
      id: uuidv1() 
    
]);
  return ( 
      <ItemContext.Provider value=[items, setItems] >
        props.children
      </ItemContext.Provider>
   );

AddItem.js:

    import React,  useState, useContext  from 'react';
import  ItemContext  from './ItemContext';

const AddItem = () => 
  const [name, setName] = useState('');
  const [amount, setAmount] = useState('');
  const [items, setItems] = useContext(ItemContext);

  const updateName = (e) => 
    setName(e.target.value)
  

  const updateAmount = (e) => 
    setAmount(e.target.value)
  

  const addItem = (e) => 
    e.preventDefault();
    setItems(prevItems => [...prevItems, name: name, amount: amount, key: items.id])
  

  return ( 
      <form className="new-item" onSubmit=addItem>
        <input type="text" name="name" value=name onChange=updateName placeholder="Add a new item"/>
        <input type="text" name="amount" value=amount onChange=updateAmount placeholder="Amount"/>
        <button>Submit</button>
      </form>
   );

 
export default AddItem;

Item.js:

import React,  useState, useContext  from 'react';
import  ItemContext  from './ItemContext';

const Item = (name, amount, /*deleteItem*/ ) => 
  const [id, setId] = useState('');
  const [items, setItems] = useContext(ItemContext);

  const deleteItem = (id) => 
    // const newItems = items.filter(item => items.id !== id);
    // setItems(newItems);
    const newItems = Object.assign([], ...items)
    items.splice(id, 1);
    setItems(newItems);
  

  return (
    <div>
      <h3>name</h3>
      <p>amount</p>
      <button onClick=() => deleteItem(items.id) className="delete-btn">Delete</button>
    </div>
  );

 
export default Item;

ItemsList.js:

import React,  useState, useContext  from 'react';
import Item from './Item';
import  ItemContext  from './ItemContext';
import  v1 as uuidv1  from 'uuid';

const ItemsList = () => 
  const [items, setItems] = useContext(ItemContext);
  const [id, setId] = useState('');

  const deleteItem = (id) => 
    // const newItems = items.filter(item => items.id !== id);
    // setItems(newItems);
    const newItems = Object.assign([], ...items)
    items.splice(id, 1);
    setItems(newItems);
  

  return (
    <div className="items-list">
      items.map(item => (
        <Item name=item.name amount=item.amount key=uuidv1() deleteItem=deleteItem/>
      ))
    </div> 
   );

 
export default ItemsList;

【问题讨论】:

items.filter(item =&gt; items.id !== id) 应该足以从数组中删除元素。您似乎有很多重复的状态和多个删除处理程序,这可能是您的问题的一部分。哪个“状态”是真正的items 状态?哦,等等,我明白了,您正在从上下文中提取 items“状态”。 【参考方案1】:

最初,您需要为您正在创建的ItemContext 上下文提供一个有效的初始值。它的签名应该与上下文值相匹配。我建议使用对象而不是数组。

export const ItemContext = createContext(
  items: [],
  addItem: () => ,
  deleteItem: () => 
);

然后定义 addItemdeleteItem 处理程序以包含在上下文值中。您希望避免直接暴露 setItems 状态函数,以便 ItemProvider 保持对状态不变量的控制。

const initialState = [
  
    name: "Red Beans",
    amount: 23,
    id: uuidv1()
  ,
  
    name: "Nuts for Bunnies",
    amount: 33,
    id: uuidv1()
  ,
  
    name: "Chopped Tomatoes",
    amount: 2,
    id: uuidv1()
  
];

const ItemProvider = (props) => 
  const [items, setItems] = useState(initialState);

  const addItem = (item) => setItems((items) => [...items, item]);
  const deleteItem = (id) =>
    setItems((items) => items.filter((item) => item.id !== id));

  const value = 
    items,
    addItem,
    deleteItem
  ;

  return (
    <ItemContext.Provider value=value>
      props.children
    </ItemContext.Provider>
  );
;

然后在您使用它的位置解构 ItemContext 值。

AddItem.js - 确保为新项目分配一个新的 uuidV1 GUID。我认为这是您最大的问题,您将 undefined 分配给 key 属性 (key: items.id) 而不是为 id 属性创建新的 GUID。

import React,  useState, useContext  from 'react';
import  ItemContext  from './ItemContext';

const AddItem = () => 
  const [name, setName] = useState("");
  const [amount, setAmount] = useState("");
  const  addItem  = useContext(ItemContext);

  const updateName = (e) => 
    setName(e.target.value);
  ;

  const updateAmount = (e) => 
    setAmount(e.target.value);
  ;

  const submitHandler = (e) => 
    e.preventDefault();
    addItem(
      name: name,
      amount: amount,
      id: uuidv1() // <-- new GUID here!!
    );
  ;

  return (
    <form className="new-item" onSubmit=submitHandler>
      <input
        type="text"
        name="name"
        value=name
        onChange=updateName
        placeholder="Add a new item"
      />
      <input
        type="text"
        name="amount"
        value=amount
        onChange=updateAmount
        placeholder="Amount"
      />
      <button>Submit</button>
    </form>
  );
;

Item.js - 从上下文中获取 deleteItem 并确保将项目 id 传递给组件。

import React,  useState, useContext  from 'react';
import  ItemContext  from './ItemContext';

const Item = ( name, amount, id ) => 
  const  deleteItem  = useContext(ItemContext);

  return (
    <div>
      <h3>name</h3>
      <p>amount</p>
      <button onClick=() => deleteItem(id) className="delete-btn">
        Delete
      </button>
    </div>
  );
;

ItemsList.js - 将 React 键设置为当前项目 id 并将 id 作为道具传递给 `Item。

import React,  useState, useContext  from 'react';
import Item from './Item';
import  ItemContext  from './ItemContext';

const ItemsList = () => 
  const  items  = useContext(ItemContext);

  return (
    <div className="items-list">
      items.map((item) => (
        <Item
          key=item.id // <-- Static React key to item
          id=item.id // <-- Pass id as prop for delete handler to use
          name=item.name
          amount=item.amount
        />
      ))
    </div>
  );
;

演示

【讨论】:

感谢您的努力,非常感谢。现在我更清楚如何构建它了。 @ViktorHelfrih 没问题。我通常喜欢像这样测试我的较大答案,以确保所有部分都能像我怀疑你想要的那样协同工作。如果这充分解决了您删除元素的问题,那么我邀请您接受此答案,如果您发现它和解释对您有帮助,请在可能的情况下对其进行投票。干杯,祝你好运。 我尝试将此项目连接到 firebase 数据库。但不知何故,我仍然面临问题,例如。添加新项目时状态不会立即更新,并且删除功能不起作用。我尝试将 item 组件复制到 itemslist 组件中,但没有成功。我发现我在useEffect中做了一个无限循环。现在我修复了它,但不确定它是否可以。我简直不敢相信我找不到像这样正常工作的简单应用程序的解决方案。或者也许我应该在某处添加更多 useEffects。如果你有时间可以看看我上传的代码吗?

以上是关于在 ReactJS 中删除项目,使用 useState 和 useContext的主要内容,如果未能解决你的问题,请参考以下文章

删除使用材质 ui 和 Reactjs 创建的列表中的任何项目

Redux/Flux(使用 ReactJS)和动画

解雇reactjs中的项目的问题

从 ReactJS 中的数组中删除复杂组件

React JS:从 localStorage 中删除一个项目

REACTJs:如何更改 Material-Table 中编辑和删除图标的颜色和大小?