-
Notifications
You must be signed in to change notification settings - Fork 116
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
Maximum call stack exceeded with salePrice ref (video) #2
Comments
Same problem, and I find out that it's because the trigger function do not change the So I make some change in the dep.forEach((innerEffect) => {
effect(innerEffect);
}); this change the |
Glad I'm not the only one who ran into this issue! Both of the above look like good solutions. I went ahead and put them into my own notes in case I come back to look at this later. Thanks for bringing this up! |
Following @Eugene930's example, should we also change the Should it instead temporarily replace the active effect and then re-place it when it is done? Such as the following: function effect(eff) {
const prevEffect = activeEffect
activeEffect = eff
activeEffect()
activeEffect = prevEffect
} |
Yes we should change. I think you could take a look at vue3's reactivity repo, they use a better way: stack , to achieve that. |
I was just about to make a pr for a fix that I came up with, then I saw that there is already an issue about this. I simply introduced a new variable function reactivity() {
const targetMap = new WeakMap();
let activeEffect = null;
let skipTrack = false;
function effect(eff) {
activeEffect = eff;
activeEffect();
activeEffect = null;
}
function track(target, key) {
if (skipTrack || !activeEffect) {
return;
}
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
function runEffects(dep) {
skipTrack = true;
dep.forEach(eff => eff());
skipTrack = false;
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) {
return;
}
const dep = depsMap.get(key);
if (!dep) {
return;
}
runEffects(dep);
}
function reactive(target) {
const handler = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
track(target, key);
return result;
},
set(target, key, value, receiver) {
const oldValue = target[key];
const result = Reflect.set(target, key, value, receiver);
if (result && oldValue !== value) {
trigger(target, key);
}
return result;
}
}
return new Proxy(target, handler);
}
function ref(raw) {
const r = {
get value() {
track(r, 'value');
return raw;
},
set value(newValue) {
const oldValue = raw;
raw = newValue;
if (newValue !== oldValue) {
trigger(r, 'value');
}
}
}
return r;
}
function computed(getter) {
let result = ref(null);
effect(() => {
result.value = getter();
});
return result;
}
return { effect, reactive, ref, computed, };
}
const { effect, reactive, ref, computed } = reactivity();
const product = reactive({ price: 10, quantity: 2 });
const salePrice = ref(0);
let total = 0;
console.log(total, salePrice.value); |
In the course video (but not the text below), the
salePrice
effect is declared after thetotal
effect. This causes an infinite loop.(Example of order in video)
I added a check in the ref function to not set the value if it had not changed, which solved it for me:
But then I came here to investigate and I noticed the difference, so I thought I'd point it out.
The text was updated successfully, but these errors were encountered: