1 | import React from "react"
|
2 | import { patch, newSymbol } from "./utils/utils"
|
3 |
|
4 | type Disposer = () => void
|
5 |
|
6 | const protoStoreKey = newSymbol("disposeOnUnmountProto")
|
7 | const instStoreKey = newSymbol("disposeOnUnmountInst")
|
8 |
|
9 | function runDisposersOnWillUnmount() {
|
10 | ;[...(this[protoStoreKey] || []), ...(this[instStoreKey] || [])].forEach(propKeyOrFunction => {
|
11 | const prop =
|
12 | typeof propKeyOrFunction === "string" ? this[propKeyOrFunction] : propKeyOrFunction
|
13 | if (prop !== undefined && prop !== null) {
|
14 | if (Array.isArray(prop)) prop.map(f => f())
|
15 | else prop()
|
16 | }
|
17 | })
|
18 | }
|
19 |
|
20 | export function disposeOnUnmount(target: React.Component<any, any>, propertyKey: PropertyKey): void
|
21 | export function disposeOnUnmount<TF extends Disposer | Array<Disposer>>(
|
22 | target: React.Component<any, any>,
|
23 | fn: TF
|
24 | ): TF
|
25 |
|
26 | export function disposeOnUnmount(
|
27 | target: React.Component<any, any>,
|
28 | propertyKeyOrFunction: PropertyKey | Disposer | Array<Disposer>
|
29 | ): PropertyKey | Disposer | Array<Disposer> | void {
|
30 | if (Array.isArray(propertyKeyOrFunction)) {
|
31 | return propertyKeyOrFunction.map(fn => disposeOnUnmount(target, fn))
|
32 | }
|
33 |
|
34 | const c = Object.getPrototypeOf(target).constructor
|
35 | const c2 = Object.getPrototypeOf(target.constructor)
|
36 | // Special case for react-hot-loader
|
37 | const c3 = Object.getPrototypeOf(Object.getPrototypeOf(target))
|
38 | if (
|
39 | !(
|
40 | c === React.Component ||
|
41 | c === React.PureComponent ||
|
42 | c2 === React.Component ||
|
43 | c2 === React.PureComponent ||
|
44 | c3 === React.Component ||
|
45 | c3 === React.PureComponent
|
46 | )
|
47 | ) {
|
48 | throw new Error(
|
49 | "[mobx-react] disposeOnUnmount only supports direct subclasses of React.Component or React.PureComponent."
|
50 | )
|
51 | }
|
52 |
|
53 | if (
|
54 | typeof propertyKeyOrFunction !== "string" &&
|
55 | typeof propertyKeyOrFunction !== "function" &&
|
56 | !Array.isArray(propertyKeyOrFunction)
|
57 | ) {
|
58 | throw new Error(
|
59 | "[mobx-react] disposeOnUnmount only works if the parameter is either a property key or a function."
|
60 | )
|
61 | }
|
62 |
|
63 |
|
64 | const isDecorator = typeof propertyKeyOrFunction === "string"
|
65 |
|
66 |
|
67 | const componentWasAlreadyModified = !!target[protoStoreKey] || !!target[instStoreKey]
|
68 | const store = isDecorator
|
69 | ?
|
70 | target[protoStoreKey] || (target[protoStoreKey] = [])
|
71 | :
|
72 | target[instStoreKey] || (target[instStoreKey] = [])
|
73 |
|
74 | store.push(propertyKeyOrFunction)
|
75 |
|
76 |
|
77 | if (!componentWasAlreadyModified) {
|
78 | patch(target, "componentWillUnmount", runDisposersOnWillUnmount)
|
79 | }
|
80 |
|
81 |
|
82 | if (typeof propertyKeyOrFunction !== "string") {
|
83 | return propertyKeyOrFunction
|
84 | }
|
85 | }
|