React Context API场景下点击购买按钮仅修改指定列表项状态问题
问题原因
purchase状态定义在ListItems根组件层级,所有渲染的列表项共用同一个状态值,只要状态变更所有项都会同步响应- 状态没有和单个列表项绑定,无法区分是哪个项触发了点击事件
- 原代码未给已购买的文本添加删除线样式,仅做了普通标签包裹
解决方案
方案1:抽离独立列表项组件(推荐,状态组件内维护,逻辑隔离)
直接把每个列表项封装为单独组件,自己维护购买状态,不需要修改context和其他父级文件:
修改后的list_items.jsx代码
import React,{useState, useContext} from "react"; import { FoodContext } from "../../context"; import "./list_items.css"; // 抽离的单个列表项组件,每个组件独立维护自身购买状态 const ListItem = ({item, onDelete}) => { const [purchase, setPurchase] = useState(false); return ( <div className="list_items"> {/* 通过类名控制删除线效果 */} <span className={purchase ? "purchased_text" : ""}>{item.name}</span> <button className="x_button" onClick={() => onDelete(item._id)}>X</button> <button className="purchase_button" onClick={() => setPurchase(!purchase)}> {purchase ? 'Purchased' : 'Purchase'} </button> </div> ) } const ListItems = () => { const [food, setFood] = useContext(FoodContext); const deleteItem = (id) => { const request = { method : 'DELETE' }; fetch(`http://localhost:3008/api/delete/${id}`, request) .then(res => res.json()) .then(data => { // 删除后同步更新全局列表数据 setFood(food.filter(item => item._id !== id)) }); }; return( <div> {!food.length ? <p>No Items Added</p> : food.map(item => <ListItem key={item._id} item={item} onDelete={deleteItem} />) } </div> ); } export default ListItems;
补充list_items.css样式
.purchased_text { text-decoration: line-through; }
方案2:购买状态存入全局context(适合需要跨组件同步购买状态的场景)
如果需要在其他组件也能拿到商品的购买状态,可以把购买标识存在全局的food数组中:
- 修改context.js中的getData方法,给每个商品新增默认未购买标识
const getData = () => { const request = { method : 'GET', } fetch("http://localhost:3008/api/get", request) .then(res => res.json()) .then(data => { // 给每个商品新增purchased字段 const processedData = data.map(item => ({...item, purchased: false})) setFood(processedData) }) };
- 修改list_items.jsx的点击逻辑,更新对应商品的购买状态
import React,{useContext} from "react"; import { FoodContext } from "../../context"; import "./list_items.css"; const ListItems = () => { const [food, setFood] = useContext(FoodContext); const deleteItem = (id) => { const request = { method : 'DELETE' }; fetch(`http://localhost:3008/api/delete/${id}`, request) .then(res => res.json()) .then(data => { setFood(food.filter(item => item._id !== id)) }); }; const togglePurchase = (id) => { setFood(food.map(item => { if(item._id === id) { return {...item, purchased: !item.purchased} } return item })) } return( <div> {!food.length ? <p>No Items Added</p> : food.map(item => <div className="list_items" key={item._id}> <span className={item.purchased ? "purchased_text" : ""}>{item.name}</span> <button className="x_button" onClick={() => deleteItem(item._id)}>X</button> <button className="purchase_button" onClick={() => togglePurchase(item._id)}>{item.purchased ? 'Purchased' : 'Purchase'}</button> </div>)} </div> ); } export default ListItems;
内容的提问来源于stack exchange,提问作者coolhack7
相关产品推荐
相关产品推荐

