-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug Report] formily react被动联动计算与预期不符合 #3837
Comments
看了下, reactive 是能复现的 https://codesandbox.io/s/old-violet-hxcn61?file=/src/index.js |
setTimeout(() => {
console.log('change a')
obs.A = 1
setTimeout(() => {
console.log('chagne b')
obs.B = 2
}, 1000)
}, 1000)
autorun(() => {
const A = obs.A
const B = obs.B
if (A !== undefined && B !== undefined) {
obs.C = A / B
console.log('calc C', obs.C)
}
}, 'C')
autorun(() => {
const C = obs.C
const B = obs.B
if (C !== undefined && B !== undefined) {
obs.D = C * B
console.log('calc D', obs.D)
}
}, 'D') 以你的demo来看,问题出在 obs.B=2这一步 感觉解决方案就是在batchStart执行的途中,假如tracker产生了新的reaction 是否可以使用 microTask的形式异步插入PendingReactions.保证前面的任务执行完毕再执行下一批。 |
我还在想,可能boundary判断需要更精细化一些,现在的问题就是响应来源有多个的时候被过滤掉了,如果做一个响应来源控制,应该是可以解决这个问题的 |
boundary 判断需要更精细化一些,通过响应源控制是可以控制。这个方法是可行的,我来处理这个 bug |
@janryWang @hchlq 想了解一些,这个boundary主要的意义是什么?我看是在21年引入的,原问题的复现链接已经失效了,没有看懂。 看起来主要目的是为了即让 Reaction 能够循环触发,又不想让它会重复执行最终爆栈。 在 一个响应式系统中,任务似乎不应当允许自身直接或者间接触发自身吧? 我测试了一下最新的 mobx autorun 逻辑,看起来并没有这个bug https://runkit.com/embed/zfkqf2qdmx5y var mobx = require("mobx")
const autorun = mobx.autorun;
const observable = mobx.observable;
const obs = observable({})
setTimeout(() => {
console.log('change a')
obs.A = 1
setTimeout(() => {
console.log('chagne b')
obs.B = 2
}, 1000)
}, 1000)
autorun(() => {
const A = obs.A
const B = obs.B
if (A !== undefined && B !== undefined) {
obs.C = A / B
console.log('calc C', obs.C)
}
})
autorun(() => {
const C = obs.C
const B = obs.B
if (C !== undefined && B !== undefined) {
obs.D = C * B
console.log('calc D', obs.D)
}
}) mobx 同样代码的效果: |
vue/reactive 也没有复现这个问题 https://runkit.com/embed/zqlwosvqxnqy var reactivity = require("@vue/reactivity")
const autorun = reactivity.effect;
const observable = reactivity.reactive;
const obs = observable({})
setTimeout(() => {
console.log('change a')
obs.A = 1
setTimeout(() => {
console.log('chagne b')
obs.B = 2
}, 1000)
}, 1000)
autorun(() => {
const A = obs.A
const B = obs.B
if (A !== undefined && B !== undefined) {
obs.C = A / B
console.log('calc C', obs.C)
}
})
autorun(() => {
const C = obs.C
const B = obs.B
if (C !== undefined && B !== undefined) {
obs.D = C * B
console.log('calc D', obs.D)
}
}) |
我发现了当 obs 有初始值 {A:1} 时,这个地方单测就能够通过。 test('autorun with multiple source', async () => {
// 如果 obs 默认是 {}, 单测会失败
// const obs = observable<any>({})
// 如果 obs 默认是 { A: 1 },则单测会通过
const obs = observable<any>({ A: 1 })
autorun(() => {
const A = obs.A
const B = obs.B
if (A !== undefined && B !== undefined) {
obs.C = A / B
console.log('calc C', obs.C)
}
})
autorun(() => {
const C = obs.C
const B = obs.B
if (C !== undefined && B !== undefined) {
obs.D = C * B
console.log('calc D', obs.D)
}
})
setTimeout(() => {
obs.A = 1
setTimeout(() => {
obs.B = 2
}, 1000)
}, 500)
await sleep(3000)
expect(obs.C).toBe(0.5)
expect(obs.D).toBe(1)
}) 我理解初始值 {A: 1} 在初始化时,是和随后进行 obs.A = 1 的调用,效果应该是等价的? 这里为什么会效果不一致? |
Reproduction link
Steps to reproduce
需求
有A、B、C、D四个字段,其中C = A / B,D = C * B
react版本有问题:https://codesandbox.io/s/admiring-glade-puqoq5?file=/src/App.js:539-551
reactive版本没问题:https://codesandbox.io/s/empty-star-pk8sic?file=/src/index.js
操作步骤
问题
为什么D会计算不出来结果?当C被计算出来之后,为什么D的onFieldReact没有再跑一次?
What is expected?
按操作步骤,能计算出D值
What is actually happening?
按操作步骤,无法计算出D值
Package
@formily/[email protected]
The text was updated successfully, but these errors were encountered: