Skip to content

Commit

Permalink
Fix #3492: throw warning when use class component and suspense
Browse files Browse the repository at this point in the history
  • Loading branch information
ario-guo committed Sep 6, 2022
1 parent f0e066f commit bd148fe
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilly-nails-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"mobx-react": patch
---

Fix #3492: throw warning when use class component and suspense
5 changes: 5 additions & 0 deletions packages/mobx-react-lite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ export { useLocalObservable } from "./useLocalObservable"
export { useLocalStore } from "./useLocalStore"
export { useAsObservableSource } from "./useAsObservableSource"
export { resetCleanupScheduleForTests as clearTimers } from "./utils/reactionCleanupTracking"
export {
addReactionToTrack,
reactionToTrackSymbol,
recordReactionAsCommitted
} from "./utils/reactionCleanupTracking"

export function useObserver<T>(fn: () => T, baseComponentName: string = "observed"): T {
if ("production" !== process.env.NODE_ENV) {
Expand Down
2 changes: 2 additions & 0 deletions packages/mobx-react-lite/src/utils/reactionCleanupTracking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { createReactionCleanupTrackingUsingFinalizationRegister } from "./create
import { createTimerBasedReactionCleanupTracking } from "./createTimerBasedReactionCleanupTracking"
export { IReactionTracking } from "./reactionCleanupTrackingCommon"

export const reactionToTrackSymbol = Symbol.for("reactionToTrackSymbol")

const {
addReactionToTrack,
recordReactionAsCommitted,
Expand Down
49 changes: 46 additions & 3 deletions packages/mobx-react/src/observerClass.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PureComponent, Component } from "react"
import { PureComponent, Component, createRef } from "react"
import {
createAtom,
_allowStateChanges,
Expand All @@ -10,6 +10,11 @@ import {
import { isUsingStaticRendering } from "mobx-react-lite"

import { newSymbol, shallowEqual, setHiddenProp, patch } from "./utils/utils"
import {
addReactionToTrack,
reactionToTrackSymbol,
recordReactionAsCommitted
} from "mobx-react-lite"

const mobxAdminProperty = $mobx || "$mobx" // BC
const mobxObserverProperty = newSymbol("isMobXReactObserver")
Expand Down Expand Up @@ -66,14 +71,40 @@ export function makeClassComponentObserver(
)
}
target.render = function () {
if (!this[reactionToTrackSymbol]) {
this[reactionToTrackSymbol] = createRef()
}
this.render = isUsingStaticRendering()
? originalRender
: createReactiveRender.call(this, originalRender)
return this.render()
}
patch(target, "componentDidMount", function () {
this[mobxIsUnmounted] = false
if (!this.render[mobxAdminProperty]) {
recordReactionAsCommitted(this[reactionToTrackSymbol])
let hasUpdated = false
if (this[reactionToTrackSymbol].current) {
this[reactionToTrackSymbol].current.mounted = true
if (this[reactionToTrackSymbol].current.changedBeforeMount) {
this[reactionToTrackSymbol].current.changedBeforeMount = false
hasUpdated = true
Component.prototype.forceUpdate.call(this)
}
!this.render[mobxAdminProperty]
} else {
const initialName = getDisplayName(this)
this[reactionToTrackSymbol].current = {
reaction: new Reaction(`${initialName}.render()`, () => {
Component.prototype.forceUpdate.call(this)
}),
mounted: true,
changedBeforeMount: false,
cleanAt: Infinity
}
hasUpdated = true
Component.prototype.forceUpdate.call(this)
}
if (!this.render[mobxAdminProperty] && !hasUpdated) {
// Reaction is re-created automatically during render, but a component can re-mount and skip render #3395.
// To re-create the reaction and re-subscribe to relevant observables we have to force an update.
Component.prototype.forceUpdate.call(this)
Expand All @@ -84,6 +115,8 @@ export function makeClassComponentObserver(
return
}

this[reactionToTrackSymbol].current = null

const reaction = this.render[mobxAdminProperty]
if (reaction) {
reaction.dispose()
Expand Down Expand Up @@ -143,13 +176,18 @@ function createReactiveRender(originalRender: any) {
try {
setHiddenProp(this, isForcingUpdateKey, true)
if (!this[skipRenderKey]) {
Component.prototype.forceUpdate.call(this)
if (this[reactionToTrackSymbol].current.mounted) {
Component.prototype.forceUpdate.call(this)
} else {
this[reactionToTrackSymbol].current.changedBeforeMount = true
}
}
hasError = false
} finally {
setHiddenProp(this, isForcingUpdateKey, false)
if (hasError) {
reaction.dispose()
this[reactionToTrackSymbol].current = null
// Forces reaction to be re-created on next render
this.render[mobxAdminProperty] = null
}
Expand All @@ -165,6 +203,11 @@ function createReactiveRender(originalRender: any) {
isRenderingPending = false
// Create reaction lazily to support re-mounting #3395
const reaction = (reactiveRender[mobxAdminProperty] ??= createReaction())

if (!this[reactionToTrackSymbol].current) {
addReactionToTrack(this[reactionToTrackSymbol], reaction, {})
}

let exception: unknown = undefined
let rendering = undefined
reaction.track(() => {
Expand Down

0 comments on commit bd148fe

Please sign in to comment.