MobX中数组排序失效及computed属性使用报错问题求助
解决MobX中排序后数组不更新及map报错问题
咱们来一步步拆解你的问题,先说说你之前操作里的几个核心错误,再给你正确的实现方案:
为什么之前的代码会报错?
你遇到的map is not a function报错,核心原因是错误地返回了MobX的computed对象,而不是实际的数组:
- 第三种尝试里,你在getter中返回
computed(() => ...),但这个computed()调用返回的是一个MobX的计算属性对象,不是数组,自然没法调用map方法。 - 另外,你直接用
Array.sort()会原地修改原数组,这违背了MobX中computed属性应该是纯函数、无副作用的原则,不仅会打乱原数组的顺序,还可能导致MobX的响应式追踪出现异常。
正确的实现方式
我们需要做到两点:一是排序时不修改原数组,二是正确定义响应式的计算属性。下面给你两种可行方案:
方案一:使用@computed装饰器(推荐,代码更清晰)
确保你的项目已经开启了装饰器支持(比如在Babel配置中添加相关插件),然后这样写:
import { extendObservable, computed } from 'mobx'; class ContactStore { constructor() { extendObservable(this, { loading: false, contact: { Name: "", Email: "", CellPhone: "", Phone: "", AllAreaOfExpertises: [], EventLog: [], qualityItems: [], Tags: [] }, AvailableTags: [] }); } // 用@computed标记这个getter为计算属性 @computed get sortedEventLog() { // 先通过扩展运算符创建原数组的副本,再排序,避免修改原数组 return [...this.contact.EventLog].sort((a, b) => b.Audit.Created.Date - a.Audit.Created.Date ); } // 添加评论的方法保持不变,但现在sortedEventLog会自动响应变化 addComment = text => { this.contact.EventLog.push({ // 你的评论对象结构,包含Audit.Created.Date等字段 text, Audit: { Created: { Date: Date.now() } } }); }; }
方案二:在extendObservable中直接定义computed属性
如果不想用装饰器,可以在constructor的extendObservable里直接定义计算属性:
import { extendObservable, computed } from 'mobx'; class ContactStore { constructor() { extendObservable(this, { loading: false, contact: { Name: "", Email: "", CellPhone: "", Phone: "", AllAreaOfExpertises: [], EventLog: [], qualityItems: [], Tags: [] }, AvailableTags: [], // 直接定义computed属性 sortedEventLog: computed(() => [...this.contact.EventLog].sort((a, b) => b.Audit.Created.Date - a.Audit.Created.Date ) ) }); } addComment = text => { this.contact.EventLog.push({ text, Audit: { Created: { Date: Date.now() } } }); }; }
视图层的正确使用
现在你可以在视图中直接绑定this.props.store.sortedEventLog,它会自动响应EventLog的变化,每次添加新评论后都会重新计算排序后的数组:
// 示例React组件中的使用 render() { return ( <div> {this.props.store.sortedEventLog.map(comment => ( <div key={comment.id}>{comment.text}</div> ))} </div> ); }
关键知识点回顾
- 避免原地修改数组:
Array.sort()是原地排序,一定要先创建副本(用[...arr]或arr.slice())再排序,保证原数组的纯净性。 - computed属性的正确定义:要么用
@computed装饰getter,要么在extendObservable中用computed()包裹计算逻辑,且计算逻辑必须返回最终值(比如数组),而不是computed对象。 - 响应式追踪:MobX会自动追踪computed属性依赖的observable值(这里是
contact.EventLog),当依赖变化时,computed属性会自动重新计算。
内容的提问来源于stack exchange,提问作者Roger Johansson
相关产品推荐
相关产品推荐

