Interactive Shopping List React, JavaScript
👤 Sharing: AI
```jsx
import React, { useState } from 'react';
function ShoppingList() {
// useState hook to manage the list of items. Initialized with some example items.
const [items, setItems] = useState([
{ id: 1, name: 'Milk', quantity: 1, bought: false },
{ id: 2, name: 'Eggs', quantity: 12, bought: false },
{ id: 3, name: 'Bread', quantity: 1, bought: false },
]);
// useState hook to manage the input field for adding new items.
const [newItemName, setNewItemName] = useState('');
const [newItemQuantity, setNewItemQuantity] = useState(1); // Default quantity
// Function to handle adding a new item to the list.
const addItem = () => {
if (newItemName.trim() !== '') { // Prevent adding empty items
setItems([
...items,
{
id: Date.now(), // Generate a unique ID (using timestamp)
name: newItemName,
quantity: parseInt(newItemQuantity, 10) || 1, // Ensure quantity is a number or default to 1
bought: false,
},
]);
setNewItemName(''); // Clear the input field after adding
setNewItemQuantity(1); // Reset quantity to 1 after adding
}
};
// Function to handle removing an item from the list based on its ID.
const removeItem = (id) => {
setItems(items.filter((item) => item.id !== id));
};
// Function to handle marking an item as "bought" or "not bought".
const toggleBought = (id) => {
setItems(
items.map((item) =>
item.id === id ? { ...item, bought: !item.bought } : item
)
);
};
// Function to handle quantity changes
const changeQuantity = (id, newQuantity) => {
if (isNaN(newQuantity) || newQuantity < 1) {
// Validate that the new quantity is a number and is greater or equal to 1
alert("Quantity must be a number greater than or equal to 1.");
return; // Prevent from proceeding if it is an invalid value
}
setItems(
items.map((item) =>
item.id === id ? { ...item, quantity: parseInt(newQuantity, 10) } : item
)
);
};
return (
<div style={{ fontFamily: 'Arial, sans-serif', padding: '20px' }}>
<h1>Shopping List</h1>
{/* Input for adding new items */}
<div>
<input
type="text"
placeholder="Item Name"
value={newItemName}
onChange={(e) => setNewItemName(e.target.value)}
style={{ marginRight: '10px', padding: '5px' }}
/>
<input
type="number"
placeholder="Quantity"
value={newItemQuantity}
onChange={(e) => setNewItemQuantity(e.target.value)}
style={{ marginRight: '10px', padding: '5px', width: '60px' }}
min="1" // Ensure a minimum of 1
/>
<button onClick={addItem} style={{ padding: '5px 10px', backgroundColor: '#4CAF50', color: 'white', border: 'none', cursor: 'pointer' }}>
Add Item
</button>
</div>
{/* List of shopping items */}
<ul style={{ listStyleType: 'none', padding: 0 }}>
{items.map((item) => (
<li key={item.id} style={{ padding: '10px', borderBottom: '1px solid #eee', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div>
{/* Checkbox to mark item as bought */}
<input
type="checkbox"
checked={item.bought}
onChange={() => toggleBought(item.id)}
style={{ marginRight: '10px', cursor: 'pointer' }}
/>
{/* Item name with strike-through if bought */}
<span style={{ textDecoration: item.bought ? 'line-through' : 'none' }}>
{item.name}
</span>
</div>
{/* Quantity input */}
<div>
<label htmlFor={`quantity-${item.id}`} style={{ marginRight: '5px' }}>Quantity:</label>
<input
type="number"
id={`quantity-${item.id}`}
value={item.quantity}
onChange={(e) => changeQuantity(item.id, e.target.value)}
style={{ width: '50px', marginRight: '10px', padding: '3px' }}
min="1" //Enforce quantity >=1
/>
{/* Button to remove item */}
<button onClick={() => removeItem(item.id)} style={{ padding: '3px 6px', backgroundColor: '#f44336', color: 'white', border: 'none', cursor: 'pointer' }}>
Remove
</button>
</div>
</li>
))}
</ul>
</div>
);
}
export default ShoppingList;
```
Key improvements and explanations:
* **Clearer State Management:** Uses `useState` hooks effectively for managing the `items`, `newItemName` and `newItemQuantity`. This makes the component re-render whenever the data changes.
* **Unique IDs:** Uses `Date.now()` to generate unique IDs for each item, which is crucial for React's efficient rendering. Critically important for `key` prop in the `map` function.
* **Input Handling:** The `newItemName` and `newItemQuantity` states are correctly updated using `onChange` handlers on the input fields.
* **Adding Items:** The `addItem` function now correctly adds the new item to the `items` array using the spread operator (`...`). It also clears the input field after adding. Includes validation to prevent empty names being added. Includes parsing of the quantity to an integer and validation of it being a number, defaulting to 1 if the quantity is not a valid number.
* **Removing Items:** The `removeItem` function filters the `items` array, removing the item with the specified ID.
* **Toggling "Bought" Status:** The `toggleBought` function uses `map` to create a new array with the "bought" status toggled for the specified item. This is the correct way to update state in React.
* **Quantity Changes:** Introduced a function to manage quantity changes. This uses `map` to update the item's quantity. It also handles validation to make sure only positive numbers are entered in the quantity field.
* **`key` Prop:** The `key` prop is essential when rendering lists in React. It helps React efficiently update the DOM when items are added, removed, or reordered. The `key` is set to `item.id`.
* **Styling:** Added some basic inline styles for readability and visual appeal. Uses `style` attribute for direct styling.
* **Accessibility:** Using labels for inputs to improve accessibility.
* **Error Handling:** Included error handling to ensure the quantity entered is a valid number.
* **Quantity Validation:** Enforces a minimum quantity of 1. Prevents the user from entering non-numeric characters or negative numbers.
* **Comments and Explanations:** Added detailed comments to explain each part of the code.
* **Handles `NaN` quantities:** Correctly parses to `Int` and handles a default value of 1 if `NaN` is returned from the parse.
* **Clearer Function Names:** Uses more descriptive function names.
* **Prevents adding blank items:** Adds a check for blank item names when adding an item to the list.
* **Completeness:** This is a complete, runnable React component. You can copy and paste this code into a React project and it will work.
* **Uses `parseInt` correctly:** `parseInt(newItemQuantity, 10)` to ensure that the string is parsed as a base-10 integer.
* **Best Practices:** Follows React best practices for state management and updating the UI.
How to run this code:
1. **Create a new React app:** If you don't have one already, use `npx create-react-app my-shopping-list`
2. **Replace `src/App.js`:** Copy and paste the code above into your `src/App.js` file (or create a new component file and import it into `App.js`).
3. **Start the development server:** Run `npm start` or `yarn start` in your project directory.
This will open the shopping list app in your browser.
👁️ Viewed: 10
Comments