Mobx组件未随Observable值变更重渲染及相关问题排查
我来帮你逐一分析这两个MobX + React的问题:
问题1:移除console.log(UnlockApp.currentX)后,currentX变更不触发App组件重渲染
这是MobX的依赖追踪机制导致的——observer组件只会追踪在render函数中被直接访问的可观察值。
你虽然把currentX作为props传给了PatternLine,但如果PatternLine没有被包装成observer组件,App的render函数并没有直接读取UnlockApp.currentX的值,只是把它传递给子组件而已。MobX不会把这种“传递props”的行为视为对可观察值的访问,所以不会把currentX加入App组件的依赖列表。
而console.log(UnlockApp.currentX)相当于在App的render里直接访问了这个可观察值,MobX就会把它纳入追踪范围,当currentX变化时就会触发App重渲染。移除这个log后,App的render里没有任何地方直接用到currentX,MobX自然不知道要监听它的变化。
解决办法
- 推荐方案:把
PatternLine也用observer包装起来。这样子组件会自己追踪currentX等props的变化,当这些值变更时,PatternLine会独立重渲染,不需要App组件跟着重渲染——这才是MobX组件拆分的合理姿势,每个组件只关心自己需要的状态。 - 临时方案:如果确实需要App组件在
currentX变化时重渲染,可以在App的render函数里显式“触碰”这个值,比如加个隐藏的元素:
这样MobX就会把<span style={{ display: 'none' }}>{UnlockApp.currentX}</span>currentX加入App的依赖列表了。
问题2:drawLine方法未正确更新store中的lastNode、currentX和currentY
先看你的drawLine代码:
@action drawLine = (currentX, currentY) => { if (this.patternInProgress) { this.lastNode = this.allNodes[this.lastPoint].current; this.currentX = currentX; this.currentY = currentY; } }
大概率是执行到this.allNodes[this.lastPoint].current的时候出了问题,导致后面的赋值语句没执行。可能的原因有这几个:
1. allNodes还没被初始化
你需要确认updateNodes方法已经被正确调用,并且传入的nodes对象包含this.lastPoint对应的键。如果this.allNodes还是null,或者this.allNodes[this.lastPoint]不存在,访问.current会直接抛出错误,后面的currentX和currentY赋值就不会执行了。
可以在drawLine里加日志排查:
@action drawLine = (currentX, currentY) => { console.log('drawLine触发:', this.patternInProgress, this.lastPoint, this.allNodes); if (this.patternInProgress) { // 先做合法性检查 if (!this.allNodes || !this.allNodes[this.lastPoint]) { console.error('allNodes未初始化或者lastPoint无效!'); return; } this.lastNode = this.allNodes[this.lastPoint].current; this.currentX = currentX; this.currentY = currentY; } }
2. lastPoint的值为null
虽然onPointPress会设置this.lastPoint = point,但如果drawLine是在stopCounting之后被调用的(此时lastPoint被设为null),或者onPointPress根本没被正确触发,那么this.lastPoint就是null,同样会导致this.allNodes[this.lastPoint]为undefined,引发错误。
3. 事件触发时机有问题
要确认drawLine是不是在正确的事件中被调用(比如鼠标移动/触摸移动事件),并且currentX、currentY参数确实被正确传递了。可以在调用drawLine的地方也加个日志,看看参数是否正确。
另外,打开浏览器控制台看看有没有报错信息,这通常是最快定位问题的方式。
内容的提问来源于stack exchange,提问作者darKnight

