Skip to content

Commit 1e011c9

Browse files
authored
Merge pull request #498 from japgolly/unmounted-dom
Fix getDOMNode on unmounted components
2 parents 1d39258 + 184123b commit 1e011c9

File tree

8 files changed

+30
-11
lines changed

8 files changed

+30
-11
lines changed

core/src/main/scala/japgolly/scalajs/react/ComponentDom.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ object ComponentDom {
6969
case null | () => Unmounted
7070
}
7171

72+
def findDOMNode(a: dom.Element | Raw.React.ComponentUntyped): ComponentDom = {
73+
val b: Raw.ReactDOM.DomNode | Null =
74+
try Raw.ReactDOM.findDOMNode(a)
75+
catch {case t: Throwable => null}
76+
apply(b)
77+
}
78+
7279
case object Unmounted extends ComponentDom {
7380
override def mounted = None
7481
}

core/src/main/scala/japgolly/scalajs/react/ReactDOM.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object ReactDOM {
1010

1111
/** For mounted components, use .getDOMNode */
1212
def findDOMNode(componentOrElement: dom.Element | Raw.React.ComponentUntyped): Option[ComponentDom.Mounted] =
13-
ComponentDom(raw.findDOMNode(componentOrElement)).mounted
13+
ComponentDom.findDOMNode(componentOrElement).mounted
1414

1515
def unmountComponentAtNode(container: dom.Node): Boolean =
1616
raw.unmountComponentAtNode(container)

core/src/main/scala/japgolly/scalajs/react/component/Js.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ object Js extends JsBaseComponentTemplate[RAW.React.ComponentClassP] {
133133
override def props = raw.props
134134
override def propsChildren = PropsChildren.fromRawProps(raw.props)
135135
override def state = raw.state
136-
override def getDOMNode = ComponentDom(RAW.ReactDOM.findDOMNode(raw))
136+
override def getDOMNode = ComponentDom.findDOMNode(raw)
137137

138138
override def setState(state: S, callback: Callback): Unit =
139139
raw.setState(state, callback.toJsFn)

core/src/main/scala/japgolly/scalajs/react/raw/ReactDOM.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ trait ReactDOM extends js.Object {
2525
final def unmountComponentAtNode(container: dom.Node): Boolean = js.native
2626

2727
// ==========================================================================
28-
// NOTE: Ensure that DomNode is kept up-to-date with this type
28+
// NOTE: Ensure that ComponentDom is kept up-to-date with this type
2929
//
3030
final type DomNode = dom.Element | dom.Text
3131
// ==========================================================================
3232

33+
@throws[js.JavaScriptException]("if arg isn't a React component or its unmounted")
3334
final def findDOMNode(componentOrElement: dom.Element | React.ComponentUntyped): DomNode | Null = js.native
3435

3536
final def createPortal(child: React.Node, container: Container): React.Node = js.native

doc/USAGE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,9 @@ React Extensions
337337
rather than just getting back a VDOM reference, the return type is an ADT like this:
338338

339339
```
340-
ComponentDom
341-
342-
ComponentDom.Mounted
340+
ComponentDom
341+
342+
ComponentDom.Mounted ComponentDom.Unmounted
343343
↑ ↑
344344
ComponentDom.Element ComponentDom.Text
345345
```

doc/changelog/1.3.0.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
There is now a proper ADT:
88

99
```
10-
ComponentDom
11-
12-
ComponentDom.Mounted
10+
ComponentDom
11+
12+
ComponentDom.Mounted ComponentDom.Unmounted
1313
↑ ↑
1414
ComponentDom.Element ComponentDom.Text
1515
```

doc/changelog/1.3.1.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## 1.3.1
2+
3+
* In the previous release `.getDOMNode` got a new data type capable of handling
4+
when the component is unmounted.
5+
Silly me forgot to actually test and catch the case when it's unmounted.
6+
This is fixed in this release.
7+

test/src/test/scala/japgolly/scalajs/react/core/ScalaComponentTest.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ object ScalaComponentPTest extends TestSuite {
149149
.componentDidCatch($ => $.setState(Some($.error.message.replaceFirst("'.+' *", ""))))
150150
.build
151151

152-
ReactTestUtils.withNewBodyElement { mountNode =>
152+
val staleDomNodeCallback = ReactTestUtils.withNewBodyElement { mountNode =>
153153
assertMountCount(0)
154154

155155
var mounted = Comp(Props(1, 2, 3)).renderIntoDOM(mountNode)
@@ -169,11 +169,15 @@ object ScalaComponentPTest extends TestSuite {
169169
mounted = Comp(null).renderIntoDOM(mountNode)
170170
assertOuterHTML(mounted.getDOMNode.asMounted().asElement(), "<div>Error: Cannot read property of null</div>")
171171
assertEq("willUnmountCount", willUnmountCount, 1)
172+
173+
mounted.withEffectsPure.getDOMNode
172174
}
173175

174176
assertMountCount(1)
175177
assertEq("willUnmountCount", willUnmountCount, 1)
176-
assertEq("recievedPropDeltas", recievedPropDeltas, Vector(Props(0, 0, 5), Props(0, 3, 0)))
178+
assertEq("receivedPropDeltas", recievedPropDeltas, Vector(Props(0, 0, 5), Props(0, 3, 0)))
179+
180+
assert(staleDomNodeCallback.runNow().mounted.isEmpty)
177181
}
178182

179183
'lifecycle2 - {

0 commit comments

Comments
 (0)