千峰React:案例二
- 游戏开发
- 2025-09-22 06:33:01

完成对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) => ( <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计算
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) => ( <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这下基本就写完了
千峰React:案例二由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“千峰React:案例二”