Shop.jsx 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /**
  2. * 购物车
  3. */
  4. import { useMemo, useState, useCallback } from 'react'
  5. const initList = [
  6. { id: 1, name: '算法导论', publish: '2006-9', price: 85, count: 1 },
  7. { id: 2, name: 'UNIX编程艺术', publish: '2016-2', price: 39, count: 1 },
  8. { id: 3, name: '编程珠玑', publish: '2020-4', price: 189, count: 1 },
  9. { id: 4, name: '代码大全', publish: '2013-8', price: 299, count: 1 },
  10. ]
  11. export default function Shop() {
  12. const [books, setBooks] = useState(initList)
  13. // ★ useMemo:仅 books 变化时重新计算总价
  14. const total = useMemo(() => {
  15. return books.reduce((sum, item) => sum + item.count * item.price, 0)
  16. }, [books])
  17. // ★ 数量 +1(不可变更新)
  18. const handleAdd = useCallback((id) => {
  19. setBooks(prev =>
  20. prev.map(b => b.id === id ? { ...b, count: b.count + 1 } : b)
  21. )
  22. }, [])
  23. // ★ 数量 -1(最小为 1)
  24. const handleReduce = useCallback((id) => {
  25. setBooks(prev =>
  26. prev.map(b => b.id === id && b.count > 1
  27. ? { ...b, count: b.count - 1 }
  28. : b
  29. )
  30. )
  31. }, [])
  32. // ★ 移除
  33. const handleRemove = useCallback((id) => {
  34. if (!window.confirm('确定从购物车中移除当前书籍么')) return
  35. setBooks(prev => prev.filter(item => item.id !== id))
  36. }, [])
  37. return (
  38. <div>
  39. <h1>🛒 购物车</h1>
  40. <table border={1} cellPadding={25} style={{ marginTop: 16, borderCollapse: 'collapse' }}>
  41. <thead>
  42. <tr style={{ background: '#f5f5f5' }}>
  43. <th>#</th>
  44. <th>书籍名称</th>
  45. <th>出版日期</th>
  46. <th>价格</th>
  47. <th>购买数量</th>
  48. <th>操作</th>
  49. </tr>
  50. </thead>
  51. <tbody>
  52. {books.map((item, index) => (
  53. <tr key={item.id}>
  54. <td>{index + 1}</td>
  55. <td>{item.name}</td>
  56. <td>{item.publish}</td>
  57. <td>¥{item.price}</td>
  58. <td>
  59. <button
  60. disabled={item.count <= 1}
  61. onClick={() => handleReduce(item.id)}
  62. >−</button>
  63. <span style={{ padding: '0 8px' }}>{item.count}</span>
  64. <button onClick={() => handleAdd(item.id)}>+</button>
  65. </td>
  66. <td>
  67. <button onClick={() => handleRemove(item.id)}>移除</button>
  68. </td>
  69. </tr>
  70. ))}
  71. </tbody>
  72. </table>
  73. <h2 style={{ marginTop: 20, color: '#e74c3c' }}>
  74. 总价格:¥{total}
  75. </h2>
  76. </div>
  77. )
  78. }