使用 useState 和 useContext 在 ReactJS 中删除项目
Deleting items in ReactJS, using useState and useContext
作为一个相当新的编程迷,我一直在使用一个简单的列出项目的应用程序。添加项目,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;
最初您需要为正在创建的 ItemContext
上下文提供一个有效的初始值。它的签名应该匹配上下文值。我建议使用对象而不是数组。
export const ItemContext = createContext({
items: [],
addItem: () => {},
deleteItem: () => {}
});
然后定义 addItem
和 deleteItem
处理程序以包含在上下文值中。您希望避免直接公开 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 49=].
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>
);
};
演示
作为一个相当新的编程迷,我一直在使用一个简单的列出项目的应用程序。添加项目,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;
最初您需要为正在创建的 ItemContext
上下文提供一个有效的初始值。它的签名应该匹配上下文值。我建议使用对象而不是数组。
export const ItemContext = createContext({
items: [],
addItem: () => {},
deleteItem: () => {}
});
然后定义 addItem
和 deleteItem
处理程序以包含在上下文值中。您希望避免直接公开 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 49=].
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>
);
};