- Fixed #701:
toJS
sometimes failing to convert objects decorated with@observable
(cause:isObservable
sometimes returned false on these objects) - Fixed typings for
when
/autorun
/reaction
; they all return a disposer function.
A deprecation message will now be printed if creating computed properties while relying on automatic inference of argumentless functions as computed values. In other words, when using observable
or extendObservable
in the following manner:
const x = observable({
computedProp: function() {
return someComputation
}
})
// Due to automatic inference now available as computed property:
x.computedProp
// And not !
x.computedProp()
Instead, to create a computed property, use:
observable({
get computedProp() {
return someComputation
}
})
or alternatively:
observable({
computedProp: computed(function() {
return someComputation
})
})
This change should avoid confusing experiences when trying to create methods that don't take arguments. The current behavior will be kept as-is in the MobX 2.* range, but from MobX 3 onward the argumentless functions will no longer be turned automatically into computed values; they will be treated the same as function with arguments. An observable reference to the function will be made and the function itself will be preserved. See for more details #532
N.B. If you want to introduce actions on an observable that modify its state, using action
is still the recommended approach:
observable({
counter: 0,
increment: action(function() {
this.counter++
})
})
- Added
move
operation to observable array, see #697
- Fixed potential clean up issue if an exception was thrown from an intercept handler
- Improved typings of
asStructure
(by @nidu, see #687) - Added support for
computed(asStructure(() => expr))
(by @yotambarzilay, see #685)
- 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
- Changes related to
toJS
as mentioned in version2.6.0
were not actually shipped. This has been fixed, so see release notes below.
- Introduced convenience
isArrayLike
: returns whether the argument is either a JS- or observable array. By @dslmeinte - Improved readme. By @DavidLGoldberg
- Improved assertion message, by @ncammarate (See #618)
- Added HashNode badge, by @sandeeppanda92
Marked as minor release as the behavior of toJS
has been changed, which might be interpreted both as bug-fix or as breaking change, depending of how you interpreted the docs
- Fixed #566: Fixed incorrect behavior of
toJS
:toJS
will now only recurse into observable object, not all objects. The new behavior is now aligned with what is suggested in the docs, but as a result the semantics changed a bit.toJSlegacy
will be around for a while implementing the old behavior. See [#589](See mobxjs#589) for more details. - Fixed #571: Don't use
instanceof
operator. Should fix issues if MobX is included multiple times in the same bundle. - Fixed #576: disallow passing actions directly to
autorun
; as they won't be tracked by @jeffijoe - Extending observable objects with other observable (objects) is now explicitly forbidden, fixes #540.
- Introduced
isComputed
- Observable objects can now have a type:
IObservableObject
, see #484 by @spiffytech - Restored 2.4 behavior of boxed observables inside observable objects, see #558
- Computed properties can now be created by using getter / setter functions. This is the idiomatic way to introduce computed properties from now on:
const box = observable({
length: 2,
get squared() {
return this.length * this.length
},
set squared(value) {
this.length = Math.sqrt(value)
}
})
- Core derivation algorithm has received some major improvements by @asterius1! See below. Pr #452, 489
- Introduced setters for computed properties, use
computed(expr, setter)
or@computed get name() { return expr } set name (value) { action }
.computed
can now be used as modifier inobservable
/extendObservable
, #421, #463 (see below for example) - Introduced
isStrictModeEnabled()
, deprecateduseStrict()
without arguments, see #464 - Fixed #505, accessing an observable property throws before it is initialized
MobX is now able track and memoize computed values while an (trans)action is running. Before 2.5, accessing a computed value during a transaction always resulted in a recomputation each time the computed value was accessed, because one of the upstream observables (might) have changed. In 2.5, MobX actively tracks whether one of the observables has changed and won't recompute computed values unnecessary. This means that computed values are now always memoized for the duration of the current action. In specific cases, this might signficantly speed up actions that extensively make decisions based on computed values.
Example:
class Square {
@observable length = 2
@computed get squared() {
return this.length * this.length
}
// mobx now supports setters for computed values
set squared(surfaceSize) {
this.length = Math.sqrt(surfaceSize)
}
// core changes make actions more efficient if extensively using computed values:
@action stuff() {
this.length = 3
console.log(this.squared) // recomputes in both 2.5 and before
console.log(this.squared) // no longer recomputes
this.length = 4
console.log(this.squared) // recomputes in both 2.5 and before
// after the action, before 2.5 squared would compute another time (if in use by a reaction), that is no longer the case
}
}
ES5 example for setters:
function Square() {
extendObservable(this, {
length: 2,
squared: computed(
function() {
return this.squared * this.squared
},
function(surfaceSize) {
this.length = Math.sqrt(surfaceSize)
}
)
})
}
- Fixed #503: map.delete returns boolean
- Fix return type of
runInAction
, #499 by @Strate - Fixed enumerability of observable array methods, see #496.
- Use TypeScript typeguards, #487 by @Strate
- Added overloads to
action
for better type inference, #500 by @Strate - Fixed #502:
extendObservable
fails on objects created withObject.create(null)
- Implemented #480 / #488: better typings for
asMap
, by @Strate
- Objects with a
null
prototype are now considered plain objects as well - Improved error message for non-converging cyclic reactions
- Fixed potential HMR issue
- Improved error message when wrongly using
@computed
, by @bb (#450) observableArray.slice
now automatically converts observable arrays to plain arrays, fixes #460- Improved error message when an uncaught exception is thrown by a MobX tracked function
@action
decorated methods are now configurable. Fixes #441- The
onBecomeObserved
event handler is now triggered when an atom is observed, instead of when it is bound as dependency. Fixes #427 and makes atoms easier to extend. - if
useStrict()
is invoked without arguments, it now returns the current value of strict mode. - the current reaction is now always passed as first argument to the callbacks of
autorun
,autorunAsync
,when
andreaction
. This allows reactions to be immediately disposed during the first run. See #438, by @andykog
- Note: the internal version of MobX has been bumped. This version has no breaking api changes, but if you have MobX loaded multiple times in your project, they all have to be upgraded to
2.4.0
. MobX will report this when starting. - Made dependency tracking and binding significant faster. Should result in huge performance improvements when working with large collections.
- Fixed typescript decorator issue, #423, #425? (by @bb)
- Fixed issue where computed values were tracked and accidentally kept alive during actions
- Fixed #406: Observable maps doesn't work with empty initial value in Safari
- Implemented #357, #348: ObservableMap and ObservableArray now support iterators. Use
@@iterator()
or iterall in ES5 environments.
- Fixed #364: Observable arrays not reacting properly to index assignments under iOS safari (mobile) 9.1.1 By @andykog
- Fixed #387: Typings of boxed values
- Added warning when reading array entries out of bounds. See #381
- Fixed #360: Removed expensive cycle detection (cycles are still detected, but a bit later)
- Fixed #377:
toJS
serialization of Dates and Regexes preserves the original values - Fixed #379:
@action
decorated methods can now be inherited / overriden
- Fixed #186: Log a warning instead of an error if an exception is thrown in a derivation. Fixes issue where React Native would produce unusable error screens (because it shows the first logged error)
- Fixed #333: Fixed some interoperability issues in combination with
Reflect
/InversifyJS
decorators. @andykog - Fixed #333:
@observable
class properties are now owned by their instance again, meaning they will show up inObject.keys()
and.hasOwnProperty
@andykog
- Fixed #328: Fixed exception when inspecting observable in
onBecomeObserved
- Fixed #341:
array.find
now returnsundefined
instead ofnull
when nothing was found, behavior now matches the docs. (By @hellectronic)
- Fixed #327: spy not working with runInAction
Usage:
whyRun()
whyRun(Reaction object / ComputedValue object / disposer function)
whyRun(object, "computed property name")
whyRun
is a small utility that can be used inside computed value or reaction (autorun
, reaction
or the render
method of an observer
React component)
and prints why the derivation is currently running, and under which circumstances it will run again.
This should help to get a deeper understanding when and why MobX runs stuff, and prevent some beginner mistakes.
This feature can probably be improved based on your feedback, so feel free to file issues with suggestions!
@observable
is now always defined on the class prototypes and not in the instances. This means that@observable
properties are enumerable, but won't appear ifObject.keys
orhasOwnProperty
is used on a class instance.- Updated semantics of
reaction
as discussed in#278
. The expression now needs to return a value and the side effect won't be triggered if the result didn't change.asStructure
is supported in these cases. In contrast to MobX 2.2, effects will no longer be run if the output of the expression didn't change.
- Introduces
isAction(fn)
#290 - If an (argumentless) action is passed to
observable
/extendObservable
, it will not be converted into a computed property. - Fixed #285: class instances are now also supported by
toJS
. Also members defined on prototypes which are enumerable are converted. - Map keys are now always coerced to strings. Fixes #308
when
,autorun
andautorunAsync
now accept custom debug names (see #293, by @jamiewinder)- Fixed #286: autorun's no longer stop working if an action throws an exception
- Implemented
runInAction
, can be used to create on the fly actions (especially useful in combination withasync/await
, see #299 - Improved performance and reduced mem usage of decorators signficantly (by defining the properties on the prototype if possible), and removed subtle differences between the implementation and behavior in babel and typescript.
- Updated logo as per #244. Tnx @osenvosem!
- Fixed issue #267: exception when
useStrict(true)
was invoked in combination with@observable
attributes when using Babel - Fixed issue #269: @action in combination with typescript targeting ES6 and reflect.ts
- Improved compatibility with
JSON.stringify
, removed incorrect deprecation message - Improved some error messages
- Fixed issue where typescript threw a compile error when using
@action
without params on a field - Fixed issue where context was accidentally shared between class instances when using
@action
on a field
See the release announcement for the full details of this release:
Introduced:
action
/@action
intercept
spy
reaction
useStrict
- improved debug names
toJSON
was renamed totoJS
observable(asMap())
is the new idiomatic way to create maps- the effect of
when
is now untracked, similar to `reaction. extras.trackTransations
is deprecated, usespy
insteaduntracked
has been undeprecated- introduced / documented:
getAtom
,getDebugName
,isSpyEnabled
,spyReport
,spyReportStart
,spyReportEnd
- deprecated
extras.SimpleEventEmitter
- array splice events now also report the
added
collection andremovedCount
- Fixed a false negative in cycle detection, as reported in #236
- Fixed #236, #237 call stack issues when working with large arrays
- Fix #222 (by @andykog) run
observe
callback of computed properties in untracked mode.
- Fixed #201 (see also #160), another iOS enumerability issue... By @luosong
- Fixed #191, when using babel, complex field initializers where shared. By @andykog
- Added
lib/mobx.umd.min.js
for minified cdn builds, see #85
- Improved debug names of objects created using a constructor
- Fixed(?) some issues with iOS7 as reported in #60 by @bstst
- Fixed issue where
autorun
's created insideautorun
's were not always kicked off. (mobx-react
'sobserver
was not affected). Please upgrade if you often use autorun. - Fixed typings of
mobx.map
, a list of entries is also acceptable. - (Experimental) Improved error recovery a bit further
- MobX is now chatty again when an exception occurs inside a autorun / computed value / React.render. Previously this was considered to be the responsibility of the surrounding code. But if exceptions were eaten this would be really tricky to debug.
- (Experimental) MobX will now do a poor attempt to recover from exceptions that occured in autorun / computed value / React.render.
resetGlobalState
is now part of themobx.extras
namespace, as it is useful for test setup, to restore inconsistent state after test failures.resetGlobalState
now also resets the caches ofcreateTransformer
, see #163.
- WIP on bower support
$transformId
property on transformed objects should be non-enumerable. Fixes #170.
- Always peek if inspecting a stale, computed value. Fixes #165.
- Fixed issue where changing an object property was tracked, which could lead to unending loops in
autorunAsync
.
- Undeprecated
observable(scalar)
(see 143) expr
no longer prints incorrect deprecated messages (see 143)- Requires
mobx
twice no longer fails.
Welcome to Mobservable MobX 2! First of all, there is the name change.
The new name is shorter and funnier and it has the right emphasis: MobX is about reactive programming.
Not about observability of data structures, which is just a technical necessity.
MobX now has its own mobxjs organization on GitHub. Just report an issue if you want to join.
All MobX 2.0 two compatible packages and repo's have been renamed. So mobx-react
, mobx-react-devtools
etc.
For the 1.0 versions, use the old mobservable
based names.
Migrating from Mobservable should be pretty straightforward as the public api is largely the same.
However there are some conceptual changes which justifies a Major version bump as it might alter the behavior of MobX in edge cases.
Besides that, MobX is just a large collection of minor improvements over Mobservable.
Make sure to remove your old mobservable
dependencies when installing the new mobx
dependencies!
autorun
is now allowed to have cycles. In Mobservable 1 an exception was thrown as soon as an autorun modified a variable which it was reading as well.
In MobX 2 these situations are now allowed and the autorun will trigger itself to be fired again immediately after the current execution.
This is fine as long as the autorun terminates within a reasonable amount of iterations (100).
This should avoid the need for work-arounds involving setTimeout
etc.
Note that computed values (created using observable(func)
are still not allowed to have cycles.
Creating an observable from a primitive or a reference no longer returns a getter/setter function, but a method with a .get
and .set
method.
This is less confusing, easier to debug and more efficient.
So to read or write from an observable scalar use:
const temperature = observable(27);
temperature.set(15); // previously: temperature(15)
temperature.get(); // previously: temperature()
observable(scalar)
has been deprecated to make the api smaller and the syntax more uniform. In practice having observable objects, arrays and decorators seems to suffice in 99% of the cases. Deprecating this functionality means that people have simply less concepts to learn. Probably creating observable scalars will continue to work for a long time, as it is important to the internals of MobX and very convenient for testing.
MobX introduced the @computed
decorator for ES6 class properties with getter functions.
It does technically the same as @observable
for getter properties. But having a separate decorator makes it easier to communicate about the code.
@observable
is for mutable state properties, @computed
is for derived values.
@computed
can now also be parameterized. @computed({asStructure: true})
makes sure that the result of a derivation is compared structurally instead of referentially with its preview value. This makes sure that observers of the computation don't re-evaluate if new structures are returned that are structurally equal to the original ones. This is very useful when working with point, vector or color structures for example. It behaves the same as the asStructure
modifier for observable values.
@computed
properties are no longer enumerable.
The core algorithm of MobX has been largely rewritten to improve the clarity, extensibility, performance and stability of the source code.
It is now possible to define your own custom observable data sources by using the Atom
class.
It is also possible to create your own reactive functions using the Reaction
class. autorun
, autorunAsync
and @observer
have now all been implemented using the concept of Reactions.
So feel free to write your own reactive constructions!
In Mobservable 1 exceptions would be caught and sometimes re-thrown after logging them.
This was confusing and not all derivations were able to recover from these exceptions.
In MobX 2 it is no longer allowed for a computed function or autorun
to throw an exception.
- MobX is roughly 20% faster
- MobX is smaller: 75KB -> 60KB unminified, and 54KB -> 30KB minified.
- Distributable builds are no longer available in the git repository, use unpkg instead:
- Commonjs build: https://unpkg.com/mobx@^2.0.0/lib/mobx.js
- Minified commonjs build: https://unpkg.com/mobx@^2.0.0/lib/mobx.min.js
- UMD build: https://unpkg.com/mobx@^2.0.0/lib/mobx.umd.js
- To use the minified build, require / import the lib from
"mobx/lib/mobx.min.js"
(or set up an alias in your webpack configuration if applicable)
- Improved debug names of all observables. This is especially visible when using
mobx-react-devtools
orextras.trackTransitions
. - Renamed
extras.SimpleEventEmitter
toSimpleEventEmitter
- Removed already deprecated methods:
isReactive
,makeReactive
,observeUntil
,observeAsync
- Removed
extras.getDNode
- Invoking
ObservableArray.peek
is no longer registered as listener - Deprecated
untracked
. It wasn't documented and nobody seems to miss it.
- Map no longer throws when
.has
,.get
or.delete
is invoked with an invalid key (#116) - Files are now compiled without sourcemap to avoid issues when loading mobservable in a debugger when
src/
folder is not available.
- Fixed: observable arrays didn't properly apply modifiers if created using
asFlat([])
orfastArray([])
- Don't try to make frozen objects observable (by @andykog)
observableArray.reverse
no longer mutates the arry but just returns a sorted copy- Updated tests to use babel6
- observableArray.sort no longer mutates the array being sorted but returns a sorted clone instead (#90)
- removed an incorrect internal state assumption (#97)
- Add bower support
- Computed value now yields consistent results when being inspected while in transaction
- Implemented #67: Reactive graph transformations. See: http://mobxjs.github.io/mobservable/refguide/create-transformer.html
- Implemented #59,
isObservable
andobserve
now support a property name as second param to observe individual values on maps and objects.
- Fixed #77: package consumers with --noImplicitAny should be able to build
- Introduced
mobservable.fastArray(array)
, in addition tomobservable.observable(array)
. Which is much faster when adding items but doesn't support enumerability (for (var idx in ar) ..
loops). - Introduced
observableArray.peek()
, for fast access to the array values. Should be used read-only.
- Fixed 71: transactions should not influence running computations
- Fixed #65; illegal state exception when using a transaction inside a reactive function. Credits: @kmalakoff
- Fixed #61; if autorun was created during a transaction, postpone execution until the end of the transaction
- Fixed exception when autorunUntil finished immediately
toJSON
now serializes object trees with cycles as well. If you know the object tree is acyclic, pass infalse
as second parameter for a performance gain.
- Exposed
ObservableMap
type - Introduced
mobservable.untracked(block)
- Introduced
mobservable.autorunAsync(block, delay)
Removed accidental log message
Fixed inconsistency when using transaction
and @observer
, which sometimes caused stale values to be displayed.
Fix incompatibility issue with systemjs bundler (see PR 52)
map.size
is now a property instead of a functionmap()
now accepts an array as entries to construct the new map- introduced
isObservableObject
,isObservableArray
andisObservableMap
- introduced
observe
, to observe observable arrays, objects and maps, similarly to Object.observe and Array.observe
extendObservable
now supports passing in multiple object properties
- added
mobservable.map()
, which creates a new map similarly to ES6 maps, yet observable. Until properly documentation, see the MDN docs.
- Stricter argument checking for several api's.
isReactive
->isObservable
makeReactive
->observable
extendReactive
->extendObservable
observe
->autorun
observeUntil
->autorunUntil
observeAsync
->autorunAsync
reactiveComponent
->observer
(inmobservable-react
package)
- dropped the
strict
andlogLevel
settings of mobservable. View functions are by default run instrict
mode,autorun
(formerly:observe
) functions innon-strict
mode (strict indicates that it is allowed to change other observable values during the computation of a view funtion). Useextras.withStrict(boolean, block)
if you want to deviate from the default behavior. observable
(formerlymakeReactive
) no longer accepts an options object. The modifiersasReference
,asStructure
andasFlat
can be used instead.- dropped the
default
export of observable - Removed all earlier deprecated functions
mobservable
now ships with TypeScript 1.6 compliant module typings, no external typings file is required anymore.mobservable-react
supports React Native as well through the import"mobservable-react/native"
.- Improved debugger support
for (var key in observablearray)
now lists the correct keys@observable
now works correct on classes that are transpiled by either TypeScript or Babel (Not all constructions where supported in Babel earlier)- Simplified error handling, mobservable will no longer catch errors in views, which makes the stack traces easier to debug.
- Removed the initial 'welcom to mobservable' logline that was printed during start-up.
- Backported Babel support for the @observable decorator from the 1.0 branch. The decorator should now behave the same when compiled with either Typescript or Babeljs.
- Introduced
strict
mode (see issues #30, #31) - Renamed
sideEffect
toobserve
- Renamed
when
toobserveUntil
- Introduced
observeAsync
. - Fixed issue where changing the
logLevel
was not picked up. - Improved typings.
- Introduces
asStructure
(see #8) andasFlat
. - Assigning a plain object to a reactive structure no longer clones the object, instead, the original object is decorated. (Arrays are still cloned due to Javascript limitations to extend arrays).
- Reintroduced
expr(func)
as shorthand formakeReactive(func)()
, which is useful to create temporarily views inside views - Deprecated the options object that could be passed to
makeReactive
. - Deprecated the options object that could be passed to
makeReactive
:- A
thisArg
can be passed as second param. - A name (for debugging) can be passed as second or third param
- The
as
modifier is no longer needed, useasReference
(instead ofas:'reference'
) orasFlat
(instead ofrecurse:false
).
- A
- Fixed issue where @observable did not properly create a stand-alone view
- Fixed bug where views where sometimes not triggered again if the dependency tree changed to much.
- Introduced
when
, which, given a reactive predicate, observes it until it returns true. - Renamed
sideEffect -> observe
- Improved logging
- Deprecated observable array
.values()
and.clone()
- Deprecated observeUntilInvalid; use sideEffect instead
- Renamed mobservable.toJson to mobservable.toJSON
- It is no longer possible to create impure views; views that alter other reactive values.
- Update links to the new documentation.
- 2nd argument of sideEffect is now the scope, instead of an options object which hadn't any useful properties
- Deprecated: reactiveComponent, reactiveComponent from the separate package mobservable-react should be used instead
- Store the trackingstack globally, so that multiple instances of mobservable can run together
- Deprecated: @observable on functions (use getter functions instead)
- Introduced:
getDependencyTree
,getObserverTree
andtrackTransitions
- Minor performance improvements