diff --git a/CHANGELOG.md b/CHANGELOG.md
index cd37e12af..dda116046 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-# 2.7.0
+# 3.0.0
### Automatic inference of computed properties has been deprecated.
@@ -84,6 +84,11 @@ See [#621](https://github.com/mobxjs/mobx/issues/621)
* `ObservableMap.toJs` (use `toJS`)
* invoking `observe` and `inject` with plain javascript objects
+# 2.6.3
+
+* Fixed #603: exceptions in transaction breaks future reactions
+* Improved typings of `toJS`
+* Introduced `setReactionScheduler`. Internal api used by mobx-react@4 to be notified when reactions will be run
# 2.6.2
diff --git a/README.md b/README.md
index eaa2b9fa3..6b25f8e63 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@ _Simple, scalable state management_
[![Coverage Status](https://coveralls.io/repos/mobxjs/mobx/badge.svg?branch=master&service=github)](https://coveralls.io/github/mobxjs/mobx?branch=master)
[![Join the chat at https://gitter.im/mobxjs/mobx](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mobxjs/mobx?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Discuss MobX on Hashnode](https://hashnode.github.io/badges/mobx.svg)](https://hashnode.com/n/mobx)
+[![OpenCollective](https://opencollective.com/mobx/backers/badge.svg)](#backers)
+[![OpenCollective](https://opencollective.com/mobx/sponsors/badge.svg)](#sponsors)
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://mobxjs.github.io/mobx/donate.html)
![npm install mobx](https://nodei.co/npm/mobx.png?downloadRank=true&downloads=true)
@@ -114,7 +116,7 @@ If you are using React, you can turn your (stateless function) components into r
```javascript
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
-import {observer} from "mobx-react";
+import {observer} from 'mobx-react';
@observer
class TodoListView extends Component {
@@ -293,3 +295,72 @@ See the [changelog](https://github.com/mobxjs/mobx/blob/master/CHANGELOG.md#200)
Was MobX key in making your project a success? Share the victory by using the [donate button](https://mobxjs.github.io/mobx/donate.html)!
MobX is developed largely in free time, so any ROI is appreciated :-).
If you leave a name you will be added to the [sponsors](https://github.com/mobxjs/mobx/blob/master/sponsors.md) list :).
+
+### Backers
+Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/mobx#backer)]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+### Sponsors
+
+Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/mobx#sponsor)]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/core/reaction.ts b/src/core/reaction.ts
index 94376fa4b..0985d72ea 100644
--- a/src/core/reaction.ts
+++ b/src/core/reaction.ts
@@ -159,10 +159,16 @@ WhyRun? reaction '${this.name}':
*/
const MAX_REACTION_ITERATIONS = 100;
+let reactionScheduler: (fn: () => void) => void = f => f();
+
export function runReactions() {
// invariant(globalState.inBatch > 0, "INTERNAL ERROR runReactions should be called only inside batch");
if (globalState.isRunningReactions === true || globalState.inTransaction > 0)
return;
+ reactionScheduler(runReactionsHelper);
+}
+
+function runReactionsHelper() {
globalState.isRunningReactions = true;
const allReactions = globalState.pendingReactions;
let iterations = 0;
@@ -184,3 +190,8 @@ export function runReactions() {
}
export const isReaction = createInstanceofPredicate("Reaction", Reaction);
+
+export function setReactionScheduler(fn: (f: () => void) => void) {
+ const baseScheduler = reactionScheduler;
+ reactionScheduler = f => fn(() => baseScheduler(f));
+}
diff --git a/src/mobx.ts b/src/mobx.ts
index b0be7c908..52db02f17 100644
--- a/src/mobx.ts
+++ b/src/mobx.ts
@@ -65,6 +65,7 @@ import { allowStateChanges } from "./core/action";
import { spyReport, spyReportEnd, spyReportStart, isSpyEnabled } from "./core/spy";
import { Lambda } from "./utils/utils";
import { isComputingDerivation } from "./core/derivation";
+import { setReactionScheduler } from "./core/reaction";
export const extras = {
allowStateChanges,
@@ -79,7 +80,8 @@ export const extras = {
shareGlobalState,
spyReport,
spyReportEnd,
- spyReportStart
+ spyReportStart,
+ setReactionScheduler
};
// Experimental or internal api's (exposed for testing for example)
diff --git a/test/api.js b/test/api.js
index 73e475f81..3ea722150 100644
--- a/test/api.js
+++ b/test/api.js
@@ -66,6 +66,7 @@ test('correct api should be exposed', function(t) {
'isComputingDerivation',
'isSpyEnabled',
'resetGlobalState',
+ 'setReactionScheduler',
'shareGlobalState',
'spyReport',
'spyReportEnd',
diff --git a/test/observables.js b/test/observables.js
index ea24bbb62..37b7bbdf2 100644
--- a/test/observables.js
+++ b/test/observables.js
@@ -1621,6 +1621,14 @@ test('603 - transaction should not kill reactions', t => {
}
+ t.equal(a.observers.length, 1)
+ t.equal(d.$mobx.observing.length, 1)
+ t.deepEqual(__mobxGlobal.inBatch, 0)
+ t.deepEqual(__mobxGlobal.inTransaction, 0)
+ t.deepEqual(__mobxGlobal.pendingReactions.length, 0)
+ t.deepEqual(__mobxGlobal.pendingUnobservations.length, 0)
+ t.deepEqual(__mobxGlobal.trackingDerivation, null)
+
t.equal(b, 2)
a.set(3)
t.equal(b, 3)
diff --git a/test/perf/perf.txt b/test/perf/perf.txt
new file mode 100644
index 000000000..2c3d56395
--- /dev/null
+++ b/test/perf/perf.txt
@@ -0,0 +1,51 @@
+
+One observers many observes one - Started/Updated in 35/26 ms.
+500 props observing sibling - Started/Updated in 3/5 ms.
+Late dependency change - Updated in 59ms.
+Unused computables - Updated in 0 ms.
+Unused observables - Updated in 9 ms.
+Array reduce - Started/Updated in 30/25 ms.
+Array loop - Started/Updated in 125/173 ms.
+Order system batched: false tracked: true Started/Updated in 448/44 ms.
+Order system batched: true tracked: true Started/Updated in 93/43 ms.
+Order system batched: false tracked: false Started/Updated in 131/65 ms.
+Order system batched: true tracked: false Started/Updated in 110/46 ms.
+
+Create array - Created in 473ms.
+
+Create array (non-recursive) Created in 169ms.
+Observable with many observers + dispose: 1240ms
+expensive sort: created 5023
+expensive sort: updated 15817
+expensive sort: disposed641
+native plain sort: updated 1643
+computed memoization 1ms
+create folders 1ms.
+create displayfolders 1ms.
+create text 271ms.
+collapse folder 1ms.
+uncollapse folder 0ms.
+change name of folder 327ms.
+search 47ms.
+unsearch 228ms.
+reactive folder tree [total]
+ 878ms.
+create folders 28ms.
+create displayfolders 1ms.
+create text 116ms.
+collapse folder 3ms.
+uncollapse folder 6ms.
+change name of folder 10ms.
+search 29ms.
+unsearch 20ms.
+reactive folder tree [total]
+ 214ms.
+create boxes 106ms.
+mutations 380ms.
+total 498ms.
+create boxes 118ms.
+mutations 945ms.
+total 1175ms.
+
+
+Completed performance suite in 30.532 sec.
\ No newline at end of file