Skip to content
This repository was archived by the owner on Dec 31, 2020. It is now read-only.
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mobxjs/mobx-react
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 5.3.3
Choose a base ref
...
head repository: mobxjs/mobx-react
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5.3.4
Choose a head ref
  • 5 commits
  • 4 files changed
  • 2 contributors

Commits on Oct 19, 2018

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    623fdec View commit details
  2. Copy the full SHA
    eb216fe View commit details
  3. added another unit test

    xaviergonz committed Oct 19, 2018
    Copy the full SHA
    3d00c03 View commit details
  4. Merge pull request #582 from mobxjs/fix-patching

    fix recursive calls for patching
    mweststrate authored Oct 19, 2018
    Copy the full SHA
    a79456d View commit details
  5. Published version 5.3.4

    mweststrate committed Oct 19, 2018
    Copy the full SHA
    a878d8d View commit details
Showing with 186 additions and 10 deletions.
  1. +4 −0 CHANGELOG.md
  2. +1 −1 package.json
  3. +23 −9 src/utils/utils.js
  4. +158 −0 test/disposeOnUnmount.test.js
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# MobX-React Changelog

### 5.3.4

* Fixed unending recursing as a result of lifecylce patching. Fixes [#579](https://github.com/mobxjs/mobx-react/issues/579) through [#582](https://github.com/mobxjs/mobx-react/pull/582) by [@xaviergonz](https://github.com/xaviergonz)

### 5.3.3

* Fixed `Cannot read property 'forEach' of undefined` exception if `disposeOnUnmount` was called conditionally. [#578](https://github.com/mobxjs/mobx-react/pull/578) by [Jef Hellemans](https://github.com/JefHellemans)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mobx-react",
"version": "5.3.3",
"version": "5.3.4",
"description": "React bindings for MobX. Create fully reactive components.",
"main": "index.js",
"jsnext:main": "index.module.js",
32 changes: 23 additions & 9 deletions src/utils/utils.js
Original file line number Diff line number Diff line change
@@ -40,19 +40,33 @@ function createOrGetCachedDefinition(methodName, enumerable) {

const wrapperMethod = function wrapperMethod(...args) {
const mixins = getMixins(this, methodName)

// avoid possible recursive calls by custom patches
if (mixins.realRunning) {
return
}
mixins.realRunning = true

const realMethod = mixins.real
let retVal

mixins.pre.forEach(pre => {
pre.apply(this, args)
})
try {
mixins.pre.forEach(pre => {
pre.apply(this, args)
})

if (realMethod !== undefined && realMethod !== null) {
realMethod.apply(this, args)
}
if (realMethod !== undefined && realMethod !== null) {
retVal = realMethod.apply(this, args)
}

mixins.post.forEach(post => {
post.apply(this, args)
})

mixins.post.forEach(post => {
post.apply(this, args)
})
return retVal
} finally {
mixins.realRunning = false
}
}
wrapperMethod[mobxMixin] = true

158 changes: 158 additions & 0 deletions test/disposeOnUnmount.test.js
Original file line number Diff line number Diff line change
@@ -262,3 +262,161 @@ describe("with observer", () => {
)
})
})

test("custom patching should work", async () => {
class BaseComponent extends React.Component {
constructor(props, context) {
super(props, context)

_makeAllSafe(this, BaseComponent.prototype, [
"componentWillMount",
"componentDidMount",
"shouldComponentUpdate",
"componentWillUpdate",
"componentWillReceiveProps",
"render",
"componentDidUpdate",
"componentWillUnmount"
])
}

componentDidMount() {
this.didMountCalled = true
}

componentWillUnmount() {
this.willUnmountCalled = true
}
}

function _makeAllSafe(obj, prototype, methodNames) {
for (let i = 0, len = methodNames.length; i < len; i++) {
_makeSafe(obj, prototype, methodNames[i])
}
}

function _makeSafe(obj, prototype, methodName) {
let classMethod = obj[methodName]
let prototypeMethod = prototype[methodName]

if (classMethod || prototypeMethod) {
obj[methodName] = function() {
this.patchRunFor = this.patchRunFor || []
this.patchRunFor.push(methodName)

let retVal

if (prototypeMethod) {
retVal = prototypeMethod.apply(this, arguments)
}
if (classMethod !== prototypeMethod) {
retVal = classMethod.apply(this, arguments)
}

return retVal
}
}
}

@observer
class C extends BaseComponent {
@disposeOnUnmount
methodA = jest.fn()
@disposeOnUnmount
methodB = jest.fn()
@disposeOnUnmount
methodC = null
@disposeOnUnmount
methodD = undefined

render() {
return null
}
}

await testComponent(
C,
ref => {
expect(ref.patchRunFor).toEqual(["render", "componentDidMount"])
expect(ref.didMountCalled).toBeTruthy()
},
ref => {
expect(ref.patchRunFor).toEqual(["render", "componentDidMount", "componentWillUnmount"])
expect(ref.willUnmountCalled).toBeTruthy()
}
)
})

it("componentDidMount should be different between components", async () => {
async function test(withObserver) {
const events = []

class A extends React.Component {
componentDidMount() {
this.didMount = "A"
events.push("mountA")
}

componentWillUnmount() {
this.willUnmount = "A"
events.push("unmountA")
}

render() {
return null
}
}

class B extends React.Component {
componentDidMount() {
this.didMount = "B"
events.push("mountB")
}

componentWillUnmount() {
this.willUnmount = "B"
events.push("unmountB")
}

render() {
return null
}
}

if (withObserver) {
A = observer(A)
B = observer(B)
}

const aRef = React.createRef()
await asyncReactDOMRender(<A ref={aRef} />, testRoot)
const caRef = aRef.current

expect(caRef.didMount).toBe("A")
expect(caRef.willUnmount).toBeUndefined()
expect(events).toEqual(["mountA"])

const bRef = React.createRef()
await asyncReactDOMRender(<B ref={bRef} />, testRoot)
const cbRef = bRef.current

expect(caRef.didMount).toBe("A")
expect(caRef.willUnmount).toBe("A")

expect(cbRef.didMount).toBe("B")
expect(cbRef.willUnmount).toBeUndefined()
expect(events).toEqual(["mountA", "unmountA", "mountB"])

await asyncReactDOMRender(null, testRoot)

expect(caRef.didMount).toBe("A")
expect(caRef.willUnmount).toBe("A")

expect(cbRef.didMount).toBe("B")
expect(cbRef.willUnmount).toBe("B")
expect(events).toEqual(["mountA", "unmountA", "mountB", "unmountB"])
}

await test(true)
await test(false)
})