应优先使用 Map.prototype.has() 进行存在性判断,因其只检测键是否存在、不受值影响;配合函数式更新创建新 Map 实例,结合 useMemo 和 React.memo 提升性能。
直接用 map.prototype.has() 替代对象属性访问或数组 includes() 做存在性判断,能避免 undefined、null 或隐式类型转换带来的误判,让状态更新逻辑更精准、可预测。
用 Map 替代普通对象做键值存在性检查
普通对象的 obj[key] !== undefined 容易漏判:当 key 对应值恰好为 undefined、false、0 或 '' 时,逻辑可能出错。而 Map.has(key) 只关心键是否真实存在于结构中,与值无关。
- ✅ 正确做法:初始化状态时用
new Map()存储已选 ID →const [selectedIds, setSelectedIds] = useState(new Map()) - ✅ 切换选中状态时:用
selectedIds.has(id)判断是否已存在,再决定是set还是delete - ❌ 避免:
selectedIds[id]或id in selectedIds(后者对 Map 无效,且对普通对象不安全)
配合函数式更新,避免重复渲染
React 中状态更新需保持不可变性。Map 本身可变,但你不能直接修改原 Map 实例传给 setState,否则 React 无法检测变化。正确方式是创建新 Map 实例,并复用旧数据。
- ✅ 添加一项:
setSelectedIds(prev => new Map(prev).set(id, true)) - ✅ 删除一项:
setSelectedIds(prev => { const next = new Map(prev); next.delete(id); return next; }) - ✅ 批量操作(如全选/取消):
setSelectedIds(prev => new Map(ids.map(id => [id, true])))
在 useEffect 或计算属性中高效过滤列表
渲染列表时常用 items.filter(item => selectedIds.has(item.id)) 获取已选项。相比 selectedIdsArray.includes(item.id),Map.has() 是 O(1) 时间复杂度,尤其在百条以上数据时差异明显。
- ✅ 渲染前预计算:
const selectedItems = items.filter(item => selectedIds.has(item.id)) - ✅ 若需频繁读取(如多个子组件),可封装为 useMemo:
useMemo(() => Array.from(selectedIds.keys()), [selectedIds]) - ⚠️ 注意:不要在 render 中反复调用
selectedIds.keys()后转数组——Map 迭代器不是稳定引用,会触发多余重渲染
与 React.memo 和 key 配合提升列表性能
当列表项依赖 Map 中的“存在性”状态(例如高亮、禁用某行),把 selectedIds.has(item.id) 的结果作为 prop 传入子组件,并确保子组件用 React.memo 包裹,能有效阻止无意义更新。
- ✅ 子组件接收布尔 prop:
- ✅ ListItem 内部用
React.memo,且 key 使用稳定 ID(如item.id) - ✅ 避免把整个
selectedIdsMap 当作 prop 传入——它每次都是新实例,memo 失效











