Repository: vigetlabs/microcosm
Pull request #291 (2017-04-10 11:54:18)

Add teardown callback to Microcosm
Domains, Effects, and Presenters have a teardown method that runs when a Microcosm shuts down. Oddly, Microcosms didn't have this behavior themselves. This commit adds a dedicated teardown hook to Microcosm, and a private `shutdown` method to trigger it.

```javascript
class Repo extends Microcosm {
  setup () {
    // runs when a Microcosm starts
  }

  teardown () {
    // runs when a Microcosm ends
  }
}
```

### Additional thoughts

#### Live reload

I kind of wonder if there's something here with live reloading. Like with a dedicated `setup` and `teardown`, you could, in theory, completely reboot a Microcosm instance.

#### Microcosms as Domains

With a getInitialState/setup/teardown, Microcosm's now implement the exact same interface as Domains. I wonder if we could do something with this

#### A public shutdown method?

I'm still not quite sure how to expose `shutdown`. What do you think? Should we keep it private? The primary use case for shutdown right now is to close out forks within Presenters. However I could see how this would be useful for component-focused apps, like Ars Arsenal and Colonel Kurtz

codecov-io: # [Codecov](https://codecov.io/gh/vigetlabs/microcosm/pull/291?src=pr&el=h1) Report
> Merging [#291](https://codecov.io/gh/vigetlabs/microcosm/pull/291?src=pr&el=desc) into [12-dev](https://codecov.io/gh/vigetlabs/microcosm/commit/f714c18a753f30ab89f2524cccf8e8f8d27a8422?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/vigetlabs/microcosm/pull/291/graphs/tree.svg?height=150&width=650&token=AaE0FLz9sU&src=pr)](https://codecov.io/gh/vigetlabs/microcosm/pull/291?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           12-dev     #291      +/-   ##
==========================================
+ Coverage   99.87%   99.87%   +<.01%     
==========================================
  Files          22       22              
  Lines         799      800       +1     
==========================================
+ Hits          798      799       +1     
  Misses          1        1
```


| [Impacted Files](https://codecov.io/gh/vigetlabs/microcosm/pull/291?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/microcosm.js](https://codecov.io/gh/vigetlabs/microcosm/pull/291?src=pr&el=tree#diff-c3JjL21pY3JvY29zbS5qcw==) | `100% <100%> (ø)` | :arrow_up: |
| [src/addons/presenter.js](https://codecov.io/gh/vigetlabs/microcosm/pull/291?src=pr&el=tree#diff-c3JjL2FkZG9ucy9wcmVzZW50ZXIuanM=) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/vigetlabs/microcosm/pull/291?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/vigetlabs/microcosm/pull/291?src=pr&el=footer). Last update [f714c18...1d1e1e4](https://codecov.io/gh/vigetlabs/microcosm/pull/291?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 27a13ac2..4ff98200 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,9 @@
 
 - Remove PropType usage from addons to prevent React 15.5.x
   deprecation warnings.
+- Added configurable `teardown` method to the Microcosm
+  prototype. This behaves similarly to `teardown` methods on other
+  Microcosm classes.
 
 ## 12.6.1
 
diff --git a/docs/api/microcosm.md b/docs/api/microcosm.md
index 75555c52..8a7cea0f 100644
--- a/docs/api/microcosm.md
+++ b/docs/api/microcosm.md
@@ -41,6 +41,11 @@ class SolarSystem extends Microcosm {
 let repo = new SolarSystem({ test: true })
 ```
 
+### `teardown()`
+
+Called whenever a Microcosm is shut down. Do any necessary clean up
+work within this callback.
+
 ### `getInitialState()`
 
 Generates the starting state for a Microcosm instance. This is the
diff --git a/package.json b/package.json
index af2827fd..db5b1055 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "microcosm",
-  "version": "12.6.1",
+  "version": "12.7.0-alpha.0",
   "private": true,
   "description": "Flux with actions at center stage. Write optimistic updates, cancel requests, and track changes with ease.",
   "main": "microcosm.js",
diff --git a/src/addons/presenter.js b/src/addons/presenter.js
index e57b207c..02134d2b 100644
--- a/src/addons/presenter.js
+++ b/src/addons/presenter.js
@@ -135,7 +135,7 @@ inherit(PresenterMediator, PureComponent, {
     this.repo.off('change', this.setModel, this)
 
     if (this.presenter.didFork) {
-      this.repo.teardown()
+      this.repo.shutdown()
     }
 
     this.presenter._beginTeardown()
diff --git a/src/microcosm.js b/src/microcosm.js
index 65503166..9be4463b 100644
--- a/src/microcosm.js
+++ b/src/microcosm.js
@@ -67,17 +67,7 @@ inherit(Microcosm, Emitter, {
   },
 
   teardown () {
-    this.effects.teardown()
-    this.domains.teardown()
-
-    // Trigger a teardown event before completely shutting down
-    this._emit('teardown', this)
-
-    // Remove this repo from history
-    this.history.removeRepo(this)
-
-    // Remove all listeners
-    this.removeAllListeners()
+    // NOOP
   },
 
   getInitialState () {
@@ -242,6 +232,32 @@ inherit(Microcosm, Emitter, {
     return new Microcosm({
       parent : this
     })
+  },
+
+  /**
+   * Close out a Microcosm:
+   *
+   * 1. Call teardown on the microcosm, domains and effects
+   * 2. Trigger a teardown event
+   * 3. Remove the microcosm from its associated history
+   * 4. Clean up all listeners
+   *
+   * @private
+   */
+  shutdown () {
+    this.teardown()
+
+    this.effects.teardown()
+    this.domains.teardown()
+
+    // Trigger a teardown event before completely shutting down
+    this._emit('teardown', this)
+
+    // Remove this repo from history
+    this.history.removeRepo(this)
+
+    // Remove all listeners
+    this.removeAllListeners()
   }
 
 })


Test patch:
diff --git a/test/addons/presenter.test.js b/test/addons/presenter.test.js
index ef64c439..5bcb9323 100644
--- a/test/addons/presenter.test.js
+++ b/test/addons/presenter.test.js
@@ -481,7 +481,7 @@ describe('::teardown', function() {
     const wrapper = mount(<Test repo={repo}/>)
 
     wrapper.unmount()
-    repo.teardown()
+    repo.shutdown()
 
     expect(spy).toHaveBeenCalledTimes(1)
   })
diff --git a/test/unit/domain/teardown.test.js b/test/unit/domain/teardown.test.js
index 13e69819..e563f8db 100644
--- a/test/unit/domain/teardown.test.js
+++ b/test/unit/domain/teardown.test.js
@@ -14,7 +14,7 @@ describe('Domain::teardown', function () {
 
     repo.addDomain('count', Counter, { test: true })
 
-    repo.teardown()
+    repo.shutdown()
 
     expect(test).toHaveBeenCalledWith(repo)
   })
diff --git a/test/unit/effect/teardown.test.js b/test/unit/effect/teardown.test.js
index a2830bcc..7e02fd5a 100644
--- a/test/unit/effect/teardown.test.js
+++ b/test/unit/effect/teardown.test.js
@@ -12,7 +12,7 @@ describe('Effect::teardown', function() {
 
     repo.addEffect(Effect)
 
-    repo.teardown()
+    repo.shutdown()
 
     expect(spy).toHaveBeenCalledWith(repo)
   })
@@ -20,7 +20,7 @@ describe('Effect::teardown', function() {
   it('does not need to implement teardown', function () {
     const repo = new Microcosm()
     repo.addEffect(class Effect {})
-    repo.teardown()
+    repo.shutdown()
   })
 
 })
diff --git a/test/unit/history/invoke.test.js b/test/unit/history/invoke.test.js
index 48f751c6..711f27da 100644
--- a/test/unit/history/invoke.test.js
+++ b/test/unit/history/invoke.test.js
@@ -7,7 +7,7 @@ describe('History::invoke', function() {
     let parent = new Microcosm()
     let child = parent.fork()
 
-    parent.on('change', () => child.teardown())
+    parent.on('change', () => child.shutdown())
 
     jest.spyOn(child, 'release')
 
diff --git a/test/unit/microcosm/events.test.js b/test/unit/microcosm/events.test.js
index 6e7d319b..b3823739 100644
--- a/test/unit/microcosm/events.test.js
+++ b/test/unit/microcosm/events.test.js
@@ -27,7 +27,7 @@ describe('Microcosm events', function () {
 
       repo.on('teardown', handler)
 
-      repo.teardown()
+      repo.shutdown()
 
       expect(handler).toHaveBeenCalledTimes(1)
       expect(handler).toHaveBeenCalledWith(repo)
@@ -61,7 +61,7 @@ describe('Microcosm events', function () {
       repo.on('teardown', handler)
       repo.off('teardown', handler)
 
-      repo.teardown()
+      repo.shutdown()
 
       expect(handler).toHaveBeenCalledTimes(0)
     })
diff --git a/test/unit/microcosm/teardown.test.js b/test/unit/microcosm/shutdown.test.js
similarity index 90%
rename from test/unit/microcosm/teardown.test.js
rename to test/unit/microcosm/shutdown.test.js
index 330250d9..40a97557 100644
--- a/test/unit/microcosm/teardown.test.js
+++ b/test/unit/microcosm/shutdown.test.js
@@ -1,6 +1,6 @@
 import Microcosm from '../../../src/microcosm'
 
-describe('Microcosm::teardown', function () {
+describe('Microcosm::shutdown', function () {
 
   it('removes all listeners', function () {
     const repo = new Microcosm()
@@ -9,7 +9,7 @@ describe('Microcosm::teardown', function () {
 
     repo.on('change', listener)
 
-    repo.teardown()
+    repo.shutdown()
 
     repo._emit('change')
 
@@ -21,7 +21,7 @@ describe('Microcosm::teardown', function () {
     const teardown = jest.fn()
 
     repo.addDomain('test', { teardown })
-    repo.teardown()
+    repo.shutdown()
 
     expect(teardown).toHaveBeenCalled()
   })
@@ -30,7 +30,7 @@ describe('Microcosm::teardown', function () {
     const repo = new Microcosm()
     const child = repo.fork()
 
-    child.teardown()
+    child.shutdown()
 
     jest.spyOn(child, 'release')
 
@@ -53,7 +53,7 @@ describe('Microcosm::teardown', function () {
         throw new Error('Should not have changed')
       })
 
-      child.teardown()
+      child.shutdown()
 
       parent.patch({ color: 'blue' })