You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 20:15:03