
完成对html文档还有css的引入,引入一下数据:
javascript
import { func } from 'prop-types'
import './购物车样式.css'
import axios from 'axios'
import { useImmer } from 'use-immer'
import { useEffect } from 'react'
function Item() {
return (
<li className='active'>
<h3>香蕉</h3>
<p>单价:5</p>
<p>
数量:
<span className='remove'>-</span>
<span>1</span>
<span className='add'>+</span>
</p>
<div className='cartbtn'>取消购买</div>
</li>
)
}
function Cart() {
const [list, setList] = useImmer([])
useEffect(() => {
axios.get('../public/cartData.json').then((res) => {
console.log(res)
})
})
return (
<div className='cart'>
<ul>
<Item />
</ul>
<div className='all'>
总金额:<span>5</span>元
</div>
</div>
)
}
export default Cart

然后判断数据是否存在:

刚刚数字一直在疯涨,导致他疯涨的原因是我的useEffect没加依赖数组,还有axios的url,如果我的数据文件在public里,可以直接从根目录访问(好像学过),要写成这样👇
javascript
useEffect(() => {
axios.get('/cartData.json').then((res) => {
if (res.data.errcode === 0) {
//map来给购物车添加
setList(res.data.list.map((item) => ({...item,active:false})))
}
})
},[])
还有一个无语的bug是箭头函数的return每次都会加大括号忘记加retuen,不加return又会格式化到下一行
对每个按钮绑上onClick事件,再给每个按钮绑上id:
javascript
import { func } from 'prop-types'
import './购物车样式.css'
import axios from 'axios'
import { useImmer } from 'use-immer'
import { useEffect } from 'react'
function Item({id,name,price,number,active,handleAdd}) {
return (
//active初始根据active的值判定
<li className={ active?'active':''}>
<h3>{ name}</h3>
<p>单价:{ price}</p>
<p>
数量:
<span className='remove'>-</span>
<span>{ number}</span>
<span className='add'>+</span>
</p>
<div className='cartbtn' onClick={()=>handleAdd(id)}>{ active?'取消购买':'添加购物车'}</div>
</li>
)
}
function Cart() {
const [list, setList] = useImmer([])
useEffect(() => {
axios.get('/cartData.json').then((res) => {
if (res.data.errcode === 0) {
//map来给购物车添加
setList(res.data.list.map((item) => ({ ...item, active: false })))
}
})
}, [])
const handleAdd=(id) => {
setList((draft) => {
const value = draft.find((item) => item.id === id)
value.active=!value.active
})
}
return (
<div className='cart'>
<ul>
{list.map((item) => <Item key={item.id} {...item} handleAdd={handleAdd} />)}
</ul>
<div className='all'>
总金额:<span>5</span>元
</div>
</div>
)
}
export default Cart

增加修改数量的功能
javascript
import { func } from 'prop-types'
import './购物车样式.css'
import axios from 'axios'
import { useImmer } from 'use-immer'
import { useEffect } from 'react'
function Item({
id,
name,
price,
number,
active,
handleAdd,
handleNumberChange,
}) {
return (
//active初始根据active的值判定
<li className={active ? 'active' : ''}>
<h3>{name}</h3>
<p>单价:{price}</p>
<p>
数量:
<span className='remove' onClick={()=>handleNumberChange(id, -1)}>
-
</span>
<span>{number}</span>
<span className='add' onClick={()=>handleNumberChange(id, +1)}>
+
</span>
</p>
<div className='cartbtn' onClick={() => handleAdd(id)}>
{active ? '取消购买' : '添加购物车'}
</div>
</li>
)
}
function Cart() {
const [list, setList] = useImmer([])
useEffect(() => {
axios.get('/cartData.json').then((res) => {
if (res.data.errcode === 0) {
//map来给购物车添加
setList(res.data.list.map((item) => ({ ...item, active: false })))
}
})
}, [])
const handleAdd = (id) => {
setList((draft) => {
const value = draft.find((item) => item.id === id)
value.active = !value.active
})
}
const handleNumberChange = (id, num) => {
setList((draft) => {
const value = draft.find((item) => item.id === id)
if (value.number === 0 && num < 0) {
return
}
value.number += num
})
}
return (
<div className='cart'>
<ul>
{list.map((item) => (
<Item
key={item.id}
{...item}
handleAdd={()=>handleAdd(item.id)}
handleNumberChange={(num)=>handleNumberChange(item.id,num)}//注意传参问题,前面的num是onClick传递的
/>
))}
</ul>
<div className='all'>
总金额:<span>5</span>元
</div>
</div>
)
}
export default Cart
如果你写成 handleNumberChange={() => handleNumberChange(item.id, num)}
,num
的值无法动态传递,因为 num
是在 Item
组件的 onClick
事件中才确定的。
加入计算总金额功能,用filter选择被加入购物车的商品,reduce计算
javascript
const all = list
.filter((item) => item.active)
.reduce((init, item) => init + item.number * item.price, 0)
每次改变状态时都会重新渲染,提升性能,使用memo,只有props不同的时候才会渲染
里面包的是函数,之前学的useCallback可以解决函数被Object.Is()判别为不同的问题
javascript
import { func } from 'prop-types'
import './购物车样式.css'
import axios from 'axios'
import { useImmer } from 'use-immer'
import { memo, useCallback, useEffect } from 'react'
const Item = memo(function Item({
id,
name,
price,
number,
active,
handleAdd,
handleNumberChange,
}) {
console.log('如果被渲染了,我就会出现')
return (
//active初始根据active的值判定
<li className={active ? 'active' : ''}>
<h3>{name}</h3>
<p>单价:{price}</p>
<p>
数量:
<span className='remove' onClick={() => handleNumberChange(id, -1)}>
-
</span>
<span>{number}</span>
<span className='add' onClick={() => handleNumberChange(id, +1)}>
+
</span>
</p>
<div className='cartbtn' onClick={() => handleAdd(id)}>
{active ? '取消购买' : '添加购物车'}
</div>
</li>
)
})
function Cart() {
const [list, setList] = useImmer([])
const all = list
.filter((item) => item.active)
.reduce((init, item) => init + item.number * item.price, 0)
useEffect(() => {
axios.get('/cartData.json').then((res) => {
if (res.data.errcode === 0) {
//map来给购物车添加
setList(res.data.list.map((item) => ({ ...item, active: false })))
}
})
}, [])
const handleAdd = useCallback((id) => {
setList((draft) => {
const value = draft.find((item) => item.id === id)
value.active = !value.active
})
})
const handleNumberChange = useCallback((id, num) => {
setList((draft) => {
const value = draft.find((item) => item.id === id)
if (value.number === 0 && num < 0) {
return
}
value.number += num
})
})
return (
<div className='cart'>
<ul>
{list.map((item) => (
<Item
key={item.id}
{...item}
handleAdd={() => handleAdd(item.id)}
handleNumberChange={(num) => handleNumberChange(item.id, num)} //注意传参问题,前面的num是onClick传递的
/>
))}
</ul>
<div className='all'>
总金额:<span>{all}</span>元
</div>
</div>
)
}
export default Cart
这下基本就写完了