React实现角色收藏去重、按钮切换及统计逻辑如何编写?
解决方案
基础问题修正
原代码存在几处基础语法和逻辑错误,需要先调整:
- useState语法错误,缺少闭合括号
- addFavorite方法未接收当前点击的角色作为参数
- 数组判断重复错误使用了
contains方法,且对象为引用类型不能直接比对 - map遍历缺少key属性,React会抛出警告
各需求实现逻辑
1. 禁止重复添加收藏
每个角色有唯一id,通过Array.some()方法判断收藏列表中是否存在相同id的角色即可,引用类型直接比对无法得到正确结果:
const isFavorited = favorites.some(fav => fav.id === character.id)
2. 收藏/取消按钮切换
在map遍历渲染时,先判断当前角色是否已收藏,动态设置按钮文字和点击事件:
- 已收藏:按钮显示「取消收藏」,点击时过滤掉当前id的角色更新收藏列表
- 未收藏:按钮显示「添加收藏」,点击时走新增逻辑
3. 统计属性平均分
遍历收藏列表累加三个属性的数值,再除以收藏总长度即可,空列表时平均分默认设为0:
const getAverageStats = () => { if (favorites.length === 0) return { strength: 0, speed: 0, intelligence: 0 } const total = favorites.reduce((prev, curr) => { return { strength: prev.strength + curr.stats.strength, speed: prev.speed + curr.stats.speed, intelligence: prev.intelligence + curr.stats.intelligence } }, { strength: 0, speed: 0, intelligence: 0 }) return { strength: (total.strength / favorites.length).toFixed(1), speed: (total.speed / favorites.length).toFixed(1), intelligence: (total.intelligence / favorites.length).toFixed(1) } }
4. 阵营数量限制
添加收藏前先统计当前两个阵营的收藏数量,如果对应阵营已达3个则阻止新增:
const goodCount = favorites.filter(fav => fav.biography["good-or-bad"] === "good").length const badCount = favorites.filter(fav => fav.biography["good-or-bad"] === "bad").length const currentCamp = character.biography["good-or-bad"] if ((currentCamp === "good" && goodCount >= 3) || (currentCamp === "bad" && badCount >=3)) { console.log(`${currentCamp}阵营收藏已达上限`) return }
完整可运行代码
import { useState } from 'react' // 角色数据 const characters = [ { id: 1, name: 'batman', biography: { "born-in": 'gotham', "good-or-bad": 'good' }, stats: { strength: 85, speed: 90, intelligence: 95 } }, { id: 2, name: 'superman', biography: { "born-in": 'krypton', "good-or-bad": 'good' }, stats: { strength: 90, speed: 85, intelligence: 80 } }, { id: 3, name: 'joker', biography: { "born-in": 'gotham', "good-or-bad": 'bad' }, stats: { strength: 70, speed: 95, intelligence: 100 } } ] export default function CharacterList() { const [favorites, setFavorites] = useState([]) // 切换收藏状态 const toggleFavorite = (character) => { const isFavorited = favorites.some(fav => fav.id === character.id) // 已收藏走取消逻辑 if (isFavorited) { setFavorites(favorites.filter(fav => fav.id !== character.id)) return } // 未收藏走新增逻辑 // 先判断阵营数量 const goodCount = favorites.filter(fav => fav.biography["good-or-bad"] === "good").length const badCount = favorites.filter(fav => fav.biography["good-or-bad"] === "bad").length const currentCamp = character.biography["good-or-bad"] if ((currentCamp === "good" && goodCount >= 3) || (currentCamp === "bad" && badCount >=3)) { console.log(`${currentCamp === 'good' ? '正义' : '邪恶'}阵营收藏已达3个上限,无法继续添加`) return } // 再判断总上限 if (favorites.length >= 6) { console.log("收藏列表已满,最多可收藏6个角色") return } // 新增收藏 setFavorites([...favorites, character]) } // 计算平均属性 const averageStats = (() => { if (favorites.length === 0) return { strength: 0, speed: 0, intelligence: 0 } const total = favorites.reduce((prev, curr) => ({ strength: prev.strength + curr.stats.strength, speed: prev.speed + curr.stats.speed, intelligence: prev.intelligence + curr.stats.intelligence }), { strength: 0, speed: 0, intelligence: 0 }) return { strength: (total.strength / favorites.length).toFixed(1), speed: (total.speed / favorites.length).toFixed(1), intelligence: (total.intelligence / favorites.length).toFixed(1) } })() return ( <div> {/* 平均属性展示 */} <div style={{ marginBottom: '20px', padding: '10px', border: '1px solid #eee' }}> <h3>收藏角色平均属性</h3> <p>平均力量:{averageStats.strength}</p> <p>平均速度:{averageStats.speed}</p> <p>平均智力:{averageStats.intelligence}</p> </div> {/* 角色列表 */} {characters.map((character) => { const isFavorited = favorites.some(fav => fav.id === character.id) return ( <div key={character.id} style={{ marginBottom: '15px', padding: '10px', border: '1px solid #ccc' }}> <h4>{character.name}</h4> <p>出生地:{character.biography["born-in"]}</p> <p>阵营:{character.biography["good-or-bad"] === 'good' ? '正义' : '邪恶'}</p> <p>力量:{character.stats.strength} | 速度:{character.stats.speed} | 智力:{character.stats.intelligence}</p> <button onClick={() => toggleFavorite(character)}> {isFavorited ? '取消收藏' : '添加收藏'} </button> </div> ) })} </div> ) }
内容的提问来源于stack exchange,提问作者Amadeo de la Peña
相关产品推荐
相关产品推荐

