Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fresh-computed-super.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"mobx": patch
---

Fix Stage 3 `@computed` overrides that delegate to a same-named parent getter via `super`.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:

- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@v1.8.0
uses: changesets/action@v1.9.0
with:
# This expects you to have a script called release which does a build for your packages and calls changeset publish
publish: npm run release
Expand Down
71 changes: 67 additions & 4 deletions docs/subclassing.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ hide_title: true

# Subclassing

Subclassing is supported with [limitations](#limitations). Most notably you can only **override actions/flows/computeds on prototype** - you cannot override _[field declarations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#field_declarations)_. Use the `override` annotation for methods/getters overridden in a subclass - see example below. Try to keep things simple and prefer composition over inheritance.
Subclassing is supported with [limitations](#limitations). Most notably you can only **override actions/flows/computeds on prototype** - you cannot override _[field declarations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#field_declarations)_. When using `makeObservable`, use the `override` annotation for methods/getters overridden in a subclass. When using modern decorators, redecorate the overridden prototype method/getter in the subclass. Try to keep things simple and prefer composition over inheritance.

<!--DOCUSAURUS_CODE_TABS-->
<!--makeObservable-->

```javascript
import { makeObservable, observable, computed, action, override } from "mobx"
import { makeObservable, observable, computed, action, flow, override } from "mobx"

class Parent {
// Annotated instance fields are NOT overridable
Expand All @@ -25,14 +28,16 @@ class Parent {
action() {}
actionBound() {}
get computed() {}
*flow() {}

constructor(value) {
makeObservable(this, {
observable: observable,
arrowAction: action
arrowAction: action,
action: action,
actionBound: action.bound,
computed: computed,
flow: flow
})
}
}
Expand All @@ -50,13 +55,15 @@ class Child extends Parent {
action() {}
actionBound() {}
get computed() {}
*flow() {}

/* --- NEW --- */
childObservable = 0;
childObservable = 0
childArrowAction = () => {}
childAction() {}
childActionBound() {}
get childComputed() {}
*childFlow() {}

constructor(value) {
super()
Expand All @@ -65,17 +72,73 @@ class Child extends Parent {
action: override,
actionBound: override,
computed: override,
flow: override,
// new
childObservable: observable,
childArrowAction: action,
childAction: action,
childActionBound: action.bound,
childComputed: computed,
childFlow: flow
})
}
}
```

<!--Modern decorators-->

```javascript
import { observable, computed, action, flow } from "mobx"

class Parent {
// Observable state fields are inherited, but should not be re-annotated
// or overridden by subclasses.
@observable accessor observable = 0

// Decorated instance fields should not be re-annotated or overridden.
@action arrowAction = () => {}

// Non-decorated instance fields are overridable.
overridableArrowAction = action(() => {})

// Decorated prototype methods/getters are overridable.
@action action() {}
@action.bound actionBound() {}
@computed get computed() {}
@flow *flow() {}
}

class Child extends Parent {
/* --- INHERITED --- */
// Unsupported: do not re-annotate or override observable/accessor fields.
// @observable accessor observable = 5
// @action arrowAction = () => {}

// OK - not decorated
overridableArrowAction = action(() => {})

// OK - prototype
@action action() {}
@action.bound actionBound() {}
@computed get computed() {
return super.computed
}
@flow *flow() {
return yield super.flow()
}

/* --- NEW --- */
@observable accessor childObservable = 0
@action childArrowAction = () => {}
@action childAction() {}
@action.bound childActionBound() {}
@computed get childComputed() {}
@flow *childFlow() {}
}
```

<!--END_DOCUSAURUS_CODE_TABS-->

## Limitations

1. Only `action`, `computed`, `flow`, `action.bound` defined **on prototype** can be **overridden** by subclass.
Expand Down
Loading