From 0d349e5fe2ae5547570c1d965672fbff93fa319d Mon Sep 17 00:00:00 2001 From: Ivan Plesskih Date: Thu, 7 Feb 2019 17:03:07 +0500 Subject: [PATCH] Decorator version of disposeOnUnmount now works with arrays (closes #637) --- README.md | 8 +++++++ src/disposeOnUnmount.js | 43 ++++++++++++++++++++--------------- test/disposeOnUnmount.test.js | 35 ++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 517b2386..a44fdb52 100644 --- a/README.md +++ b/README.md @@ -432,6 +432,14 @@ class SomeComponent extends React.Component { // decorator version @disposeOnUnmount someReactionDisposer = reaction(...) + + // decorator version with arrays + @disposeOnUnmount + someReactionDisposers = [ + reaction(...), + reaction(...) + ] + // function version over properties someReactionDisposer = disposeOnUnmount(this, reaction(...)) diff --git a/src/disposeOnUnmount.js b/src/disposeOnUnmount.js index c74fc543..d05535e9 100644 --- a/src/disposeOnUnmount.js +++ b/src/disposeOnUnmount.js @@ -3,6 +3,22 @@ import { patch, newSymbol } from "./utils/utils" const storeKey = newSymbol("disposeOnUnmount") +function checkFunc(prop) { + if (typeof prop !== "function") { + throw new Error( + "[mobx-react] disposeOnUnmount only works on functions such as disposers returned by reactions, autorun, etc." + ) + } +} + +function check(prop) { + if (Array.isArray(prop)) { + prop.map(checkFunc) + } else { + checkFunc(prop) + } +} + function runDisposersOnWillUnmount() { if (!this[storeKey]) { // when disposeOnUnmount is only set to some instances of a component it will still patch the prototype @@ -12,37 +28,28 @@ function runDisposersOnWillUnmount() { const prop = typeof propKeyOrFunction === "string" ? this[propKeyOrFunction] : propKeyOrFunction if (prop !== undefined && prop !== null) { - if (typeof prop !== "function") { - throw new Error( - "[mobx-react] disposeOnUnmount only works on functions such as disposers returned by reactions, autorun, etc." - ) - } - prop() + check(prop) + if (Array.isArray(prop)) prop.map(f => f()) + else prop() } }) this[storeKey] = [] } -export function disposeOnUnmount(target, propertyKeyOrFunction) { - if (Array.isArray(propertyKeyOrFunction)) { - return propertyKeyOrFunction.map(fn => disposeOnUnmount(target, fn)) - } - +export function disposeOnUnmount(target, propertyKeyOrFunctionOrArray) { if (!target instanceof React.Component) { throw new Error("[mobx-react] disposeOnUnmount only works on class based React components.") } - if (typeof propertyKeyOrFunction !== "string" && typeof propertyKeyOrFunction !== "function") { - throw new Error( - "[mobx-react] disposeOnUnmount only works if the parameter is either a property key or a function." - ) + if (typeof propertyKeyOrFunctionOrArray !== "string") { + check(propertyKeyOrFunctionOrArray) } // add property key / function we want run (disposed) to the store const componentWasAlreadyModified = !!target[storeKey] const store = target[storeKey] || (target[storeKey] = []) - store.push(propertyKeyOrFunction) + store.push(propertyKeyOrFunctionOrArray) // tweak the component class componentWillUnmount if not done already if (!componentWasAlreadyModified) { @@ -50,7 +57,7 @@ export function disposeOnUnmount(target, propertyKeyOrFunction) { } // return the disposer as is if invoked as a non decorator - if (typeof propertyKeyOrFunction !== "string") { - return propertyKeyOrFunction + if (typeof propertyKeyOrFunctionOrArray !== "string") { + return propertyKeyOrFunctionOrArray } } diff --git a/test/disposeOnUnmount.test.js b/test/disposeOnUnmount.test.js index 1aed6f24..085ea6e4 100644 --- a/test/disposeOnUnmount.test.js +++ b/test/disposeOnUnmount.test.js @@ -503,3 +503,38 @@ it("componentDidMount should be different between components", async () => { await doTest(true) await doTest(false) }) + +describe("should works with arrays", async () => { + test("as function", async () => { + class C extends React.Component { + methodA = jest.fn() + methodB = jest.fn() + + componentDidMount() { + disposeOnUnmount(this, [this.methodA, this.methodB]) + } + + render() { + return null + } + } + + await testComponent(C) + }) + + test("as decorator", async () => { + class C extends React.Component { + methodA = jest.fn() + methodB = jest.fn() + + @disposeOnUnmount + disposers = [this.methodA, this.methodB] + + render() { + return null + } + } + + await testComponent(C) + }) +})