完成对html文档还有css的引入,引入一下数据:
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里,可以直接从根目录访问(好像学过),要写成这样👇
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:
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
增加修改数量的功能
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) => (<Itemkey={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计算
const all = list.filter((item) => item.active).reduce((init, item) => init + item.number * item.price, 0)
每次改变状态时都会重新渲染,提升性能,使用memo,只有props不同的时候才会渲染
里面包的是函数,之前学的useCallback可以解决函数被Object.Is()判别为不同的问题
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) => (<Itemkey={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
这下基本就写完了