完成對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
這下基本就寫完了