0
var obj = mobx.observable({ arr: [{}, {}, {}] });

mobx.reaction(() => obj.arr.map(x => x.foo), (newValue) => {
    console.log(newValue);
});

var trigger = mobx.observable({ flag: false });

mobx.reaction(() => trigger.flag, newValue => {
    obj.arr.forEach((x, i) => { x.foo = 'bar'; });
});

trigger.flag = true;

vs

var obj = mobx.observable({ arr: [{}, {}, {}] });

mobx.reaction(() => obj.arr.map(x => x.foo), (newValue) => {
    console.log(newValue);
});

obj.arr.forEach((x, i) => { x.foo = 'bar'; });

Please consider two pieces of code at above. 1st trigger the side effect with console.log(newValue); once only. Which I expected to be fired 3 times like how the 2nd example works.

Is this a bug? or by design?

Danila
  • 15,606
  • 2
  • 35
  • 67
mannok
  • 1,712
  • 1
  • 20
  • 30

1 Answers1

2

Yes, this is by design.

Basically, everything you do inside your reaction is automatically wrapped in action, and everything you do inside action is transactional which will batch all mutations and updates.

Reaction is roughly speaking sugar for autorun(() => action(sideEffect)(expression))

More: https://mobx.js.org/refguide/reaction.html

Danila
  • 15,606
  • 2
  • 35
  • 67
  • Thank you @Danila. So how can I achieve sth like that in my question? e.g. pushing 3 items one by one into an observable array from an action. Cause I want know what every single item has been pushed into my observable array. (I don't think breaking synchronization like `setTimeout(() => { obsrvArr.push(x); }, 0)` is a good approach since it can be dangerous...) – mannok Jul 23 '20 at 15:48
  • Maybe use raw `autorun` for it? – Danila Jul 23 '20 at 16:12
  • Sorry I don't get what you mean – mannok Jul 23 '20 at 16:22
  • Never mind, it does not work anyway, just tried it :) Hm, not quite sure what else could help aside `setTimeout` hack – Danila Jul 23 '20 at 17:14
  • Hey @Danila. Thank you for your kindly help anyway!! – mannok Jul 23 '20 at 17:15