ReactJs中使用map遍历数组时如何动态添加表情计数属性
React表情组件渲染Firebase对应计数实现方案
现有代码结构
本地默认表情常量配置
本地通过SVG组件引入预设表情,导出表情选项数组:
import { ReactComponent as Coin } from "../assets/emojiIcons/coin.svg" import { ReactComponent as Rocket } from "../assets/emojiIcons/rocket.svg" const DEFAULT_EMOJI_OPTIONS = [ { emoji: Rocket, label: "rocket", }, { emoji: Coin, label: "coin", }, ] export { DEFAULT_EMOJI_OPTIONS }
Firebase返回的反应数据结构
接口返回的reactions数组存储每个表情的标签、计数、触发用户列表,结构如下:
reactions: [ { "emoji": "rocket", "label": "rocket", "count": 23, "users": [ "3322424", "3243242" ] }, {...}, {...} ]
待完善的组件初始代码
需要在遍历默认表情的逻辑中,插入对应表情的实时计数:
import { DEFAULT_EMOJI_OPTIONS } from "../../utils/emojis" const EmojiSection = ({reactions}) => { return ( <div className="text-white border-2 border-gray-800 rounded p-3 my-8 max-w-xs mx-auto"> {DEFAULT_EMOJI_OPTIONS.map((emoji) => ( <span key={emoji.label} onClick={() => console.log("clicked")} > <emoji.emoji width={32} height={32} /> <span> {ADD EMOJI COUNT FROM FIREBASE} </span> </span> ))} </div> ) }
实现方法
核心逻辑是通过两个数组共有的label字段做匹配,遍历本地默认表情时,从reactions数组中找到对应项取count值,未匹配到对应表情时默认显示0。
基础实现版本
直接在map循环中做匹配,适合表情数量较少的场景:
import { DEFAULT_EMOJI_OPTIONS } from "../../utils/emojis" const EmojiSection = ({reactions}) => { return ( <div className="text-white border-2 border-gray-800 rounded p-3 my-8 max-w-xs mx-auto"> {DEFAULT_EMOJI_OPTIONS.map((emoji) => { // 用label匹配当前表情对应的Firebase反应数据 const matchedReaction = reactions.find(item => item.label === emoji.label) const count = matchedReaction?.count ?? 0 return ( <span key={emoji.label} onClick={() => console.log("clicked")} className="inline-flex items-center gap-1 cursor-pointer mr-2" > <emoji.emoji width={32} height={32} /> <span>{count}</span> </span> ) })} </div> ) }
如果项目构建配置不支持可选链(?.)和空值合并运算符(??),把取值逻辑替换为const count = matchedReaction ? matchedReaction.count : 0即可。代码中新增的inline-flex等样式类是为了让表情和数字排版对齐,不需要可以直接删除。
性能优化版本
如果表情选项较多,每次遍历都执行find会产生重复计算,可以提前把reactions数组转换为以label为键的映射对象,把查询复杂度从O(n)降到O(1):
import { useMemo } from "react" import { DEFAULT_EMOJI_OPTIONS } from "../../utils/emojis" const EmojiSection = ({reactions}) => { // 仅当reactions数据变化时,重新构建映射表 const reactionMap = useMemo(() => { const map = {} reactions?.forEach(item => { map[item.label] = item }) return map }, [reactions]) return ( <div className="text-white border-2 border-gray-800 rounded p-3 my-8 max-w-xs mx-auto"> {DEFAULT_EMOJI_OPTIONS.map((emoji) => { const count = reactionMap[emoji.label]?.count ?? 0 return ( <span key={emoji.label} onClick={() => console.log("clicked")} className="inline-flex items-center gap-1 cursor-pointer mr-2" > <emoji.emoji width={32} height={32} /> <span>{count}</span> </span> ) })} </div> ) }
内容的提问来源于stack exchange,提问作者r121
相关产品推荐
相关产品推荐

