Mobx中含嵌套Promise的fromPromise计算属性未随Observable更新
看起来你碰到了MobX里异步computed属性的常见陷阱——当依赖的Observable变化时,返回fromPromise的computed没有触发更新。让我帮你拆解问题原因,再给出几个可行的解决方案:
问题根源
你的customer computed属性返回的是mobx-utils的ObservablePromise对象,MobX的computed确实会在selectedCustomerId变化时重新执行并返回新的ObservablePromise,但这里的坑在于:
- 如果你的消费代码只是持有这个ObservablePromise对象,而没有访问它的可观察内部属性(比如
value、state、error),MobX无法追踪到新的ObservablePromise的变化,自然不会触发重新渲染/计算。 - 另外,computed的缓存机制会记住上一次返回的ObservablePromise,如果你没有正确订阅新的实例,旧的订阅还是会绑定在之前的Promise上。
解决方案
方案1:在消费时访问ObservablePromise的可观察属性
确保你在响应式上下文(比如React组件的useObserver、MobX的autorun/reaction)里访问customer的内部可观察属性,这样MobX就能正确追踪依赖变化。
比如在React组件中:
import { useObserver } from "mobx-react-lite"; // 假设你通过context获取store const CustomerComponent = () => { const store = useContext(CustomerStoreContext); // 访问value/state来触发依赖追踪 const customerData = useObserver(() => store.customer.value); const customerState = useObserver(() => store.customer.state); // "pending"/"fulfilled"/"rejected" if (customerState === "pending") return <div>Loading...</div>; if (customerState === "rejected") return <div>Error loading customer</div>; return <div>{customerData?.name}</div>; };
方案2:改用Action+Observable管理异步状态(推荐)
其实MobX的computed更适合同步计算,异步逻辑用@action配合@observable状态管理会更直观,也能避免computed处理异步的各种坑。重构后的代码如下:
import { observable, action, reaction } from "mobx"; class CustomerStore { @observable selectedCustomerId = ""; @observable selectedHouseholdId = ""; // 直接用observable管理异步状态 @observable customer = null; @observable isCustomerLoading = false; @observable customerError = null; @action async fetchCustomer() { this.isCustomerLoading = true; this.customerError = null; try { this.customer = this.selectedCustomerId ? await api.getCustomerById(this.selectedCustomerId) : null; } catch (err) { this.customerError = err; } finally { this.isCustomerLoading = false; } } constructor() { // 监听selectedCustomerId变化,自动触发请求 reaction( () => this.selectedCustomerId, () => this.fetchCustomer() ); } }
这样一来,当selectedCustomerId改变时,reaction会自动调用fetchCustomer更新状态,消费时直接访问customer、isCustomerLoading这些Observable即可,逻辑更清晰,也符合MobX的最佳实践。
方案3:确保订阅新的ObservablePromise实例
如果你一定要保留computed的写法,需要确保每次computed返回新的ObservablePromise时,你都重新订阅它的变化。比如用autorun:
import { autorun } from "mobx"; // 在store初始化或者组件挂载时 autorun(() => { const customerPromise = store.customer; // 必须访问可观察属性,才能让MobX追踪到这个computed的变化 customerPromise.then( (data) => console.log("Customer updated:", data), (err) => console.error("Customer fetch failed:", err) ); });
额外检查
确认你导入的fromPromise是mobx-utils包中的——它会把普通Promise包装成带有可观察state、value、error属性的ObservablePromise,这是整个逻辑生效的前提。
内容的提问来源于stack exchange,提问作者agadzik

