Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better React 18 support #3590

Merged
merged 42 commits into from
Mar 25, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
223ce6b
wip
urugator Nov 26, 2022
fbe7604
wip
urugator Nov 27, 2022
6976dec
wip
urugator Nov 27, 2022
08ab24d
wip
urugator Dec 17, 2022
951b7e8
fix test
urugator Dec 18, 2022
abfaa7e
wip
urugator Dec 18, 2022
b5c26ca
refactor
urugator Dec 18, 2022
dfb75fd
refactor
urugator Dec 18, 2022
5006263
refactors
urugator Dec 18, 2022
229fc05
refactors
urugator Dec 18, 2022
5ca1cfe
refactor
urugator Dec 18, 2022
fa05836
use useSyncExternalStore shim
urugator Dec 18, 2022
8b8d948
typo
urugator Dec 18, 2022
27560d4
refactor
urugator Dec 18, 2022
09e471a
Merge remote-tracking branch 'upstream/main' into use-external-sync-s…
urugator Dec 18, 2022
dba0d23
useObserver: handle re-render without reaction
urugator Dec 31, 2022
2316e04
disposeOnUnmount jsdoc decprecation msg
urugator Dec 31, 2022
dd52381
disposeOnUnmount refactor
urugator Dec 31, 2022
df38953
Merge remote-tracking branch 'upstream/main' into use-external-sync-s…
urugator Jan 14, 2023
9e09fab
cleanup
urugator Feb 11, 2023
f239cb4
improve displayName/name handling
urugator Feb 11, 2023
c1f375a
fix mobx-react test
urugator Feb 11, 2023
c0ececc
try provide GC bit more time
urugator Feb 11, 2023
829dab9
try lower GC time
urugator Feb 11, 2023
0ba9985
bit more perhpas?
urugator Feb 11, 2023
8c09317
300ms
urugator Feb 11, 2023
e5492e6
document magic number
urugator Feb 11, 2023
b250f58
use number instead of Symbol as stateVersion
urugator Feb 18, 2023
e6c6246
GC 300ms -> 500ms
urugator Feb 18, 2023
b41d71e
Merge remote-tracking branch 'upstream/main' into use-external-sync-s…
urugator Mar 12, 2023
b963f7a
fix api test
urugator Mar 12, 2023
344c2cf
move use-sync-external-store to dev deps
urugator Mar 12, 2023
98940ad
changeset
urugator Mar 12, 2023
4ebb124
bump deps
urugator Mar 12, 2023
1c7e16c
deps?
urugator Mar 12, 2023
4b138b5
deps?
urugator Mar 12, 2023
21a7590
add new lines to changeset
urugator Mar 22, 2023
91e6c1a
remove test
urugator Mar 22, 2023
26fe732
Merge remote-tracking branch 'upstream/main' into use-external-sync-s…
urugator Mar 22, 2023
12ef4cc
improve comment
urugator Mar 22, 2023
98cde8b
make finalization regsitry test bit more robust
urugator Mar 22, 2023
e55c51c
increase timeout
urugator Mar 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.formatOnPaste": false
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.formatOnPaste": false
},
Expand Down
83 changes: 83 additions & 0 deletions packages/mobx-react-lite/__tests__/observer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1084,3 +1084,86 @@ test("Anonymous component displayName #3192", () => {
expect(observerError.message).toEqual(memoError.message)
consoleErrorSpy.mockRestore()
})

describe.skip("simple TODO del", () => {
let state = {}
let onStoreUpdate = () => {}

function updateStore(newState) {
state = newState
onStoreUpdate()
}

const subscribe = _onStoreUpdate => {
console.log("SUBSCRIBE")
onStoreUpdate = _onStoreUpdate
return () => {
console.log("UNSUBSCRIBE")
onStoreUpdate = () => {}
}
}

const getSnapshot = () => state

function TestCmp() {
console.log("RENDER")

React.useEffect(() => {
console.log("MOUNT")
return () => console.log("UNMOUNT")
}, [])

React.useSyncExternalStore(subscribe, getSnapshot)

return null
}

test("", async () => {
render(<TestCmp />)

act(() => {
//console.log('before update')
updateStore({})
//console.log('after update')
})
// console.log('before await');
// await (new Promise(resolve =>setTimeout(resolve, 1000)));
// console.log('after await');
// act(()=> {
// //console.log('before update')
// updateStore({});
// //console.log('after update')
// })

console.log("after act")
})

const execute = () => {
const renderings = {
child: 0,
parent: 0
}
const data = { x: 1 }
const odata = mobx.observable({ y: 1 })

const Child = observer((props: any) => {
renderings.child++
return <span>{props.data.x}</span>
})
const TestCmp = observer(() => {
renderings.parent++
return <span>{odata.y}</span>
})
return { ...render(<TestCmp />), renderings, odata }
}

test("prd", () => {
const { container, renderings, odata } = execute()
expect(renderings.parent).toBe(1)
act(() => {
odata.y++
})
expect(renderings.parent).toBe(2)
expect(container.querySelector("span")!.innerHTML).toBe("1")
})
})
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { cleanup, render } from "@testing-library/react"
import * as mobx from "mobx"
import * as React from "react"

import { useObserver } from "../src/useObserver"
import { sleep } from "./utils"
import { FinalizationRegistry } from "../src/utils/FinalizationRegistryWrapper"

// @ts-ignore
import gc from "expose-gc/function"
import { observerFinalizationRegistry } from "../src/utils/observerFinalizationRegistry"

if (typeof globalThis.FinalizationRegistry !== "function") {
throw new Error("This test must run with node >= 14")
}

expect(observerFinalizationRegistry).toBeInstanceOf(globalThis.FinalizationRegistry)

afterEach(cleanup)

test("uncommitted components should not leak observations", async () => {
if (!FinalizationRegistry) {
throw new Error("This test must run with node >= 14")
}

const store = mobx.observable({ count1: 0, count2: 0 })

// Track whether counts are observed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ import "./utils/killFinalizationRegistry"
import { act, cleanup, render } from "@testing-library/react"
import * as mobx from "mobx"
import * as React from "react"

import { useObserver } from "../src/useObserver"
import {
forceCleanupTimerToRunNowForTests,
resetCleanupScheduleForTests
} from "../src/utils/reactionCleanupTracking"
import {
CLEANUP_LEAKED_REACTIONS_AFTER_MILLIS,
CLEANUP_TIMER_LOOP_MILLIS
} from "../src/utils/reactionCleanupTrackingCommon"
REGISTRY_FINALIZE_AFTER,
REGISTRY_SWEEP_INTERVAL
} from "../src/utils/UniversalFinalizationRegistry"
import { observerFinalizationRegistry } from "../src/utils/observerFinalizationRegistry"
import { TimerBasedFinalizationRegistry } from "../src/utils/UniversalFinalizationRegistry"

expect(observerFinalizationRegistry).toBeInstanceOf(TimerBasedFinalizationRegistry)

const registry = observerFinalizationRegistry as TimerBasedFinalizationRegistry<unknown>

afterEach(cleanup)

test("uncommitted components should not leak observations", async () => {
resetCleanupScheduleForTests()
registry.finalizeAllImmediately()

// Unfortunately, Jest fake timers don't mock out Date.now, so we fake
// that out in parallel to Jest useFakeTimers
Expand Down Expand Up @@ -51,7 +52,7 @@ test("uncommitted components should not leak observations", async () => {
)

// Allow any reaction-disposal cleanup timers to run
const skip = Math.max(CLEANUP_LEAKED_REACTIONS_AFTER_MILLIS, CLEANUP_TIMER_LOOP_MILLIS)
const skip = Math.max(REGISTRY_FINALIZE_AFTER, REGISTRY_SWEEP_INTERVAL)
fakeNow += skip
jest.advanceTimersByTime(skip)

Expand All @@ -72,7 +73,7 @@ test("cleanup timer should not clean up recently-pended reactions", () => {
// 5. The commit phase runs for component A, but reaction R2 has already been disposed. Game over.

// This unit test attempts to replicate that scenario:
resetCleanupScheduleForTests()
registry.finalizeAllImmediately()

// Unfortunately, Jest fake timers don't mock out Date.now, so we fake
// that out in parallel to Jest useFakeTimers
Expand Down Expand Up @@ -106,7 +107,7 @@ test("cleanup timer should not clean up recently-pended reactions", () => {
// We force our cleanup loop to run even though enough time hasn't _really_
// elapsed. In theory, it won't do anything because not enough time has
// elapsed since the reactions were queued, and so they won't be disposed.
forceCleanupTimerToRunNowForTests()
registry.sweep()

// Advance time enough to allow any timer-queued effects to run
jest.advanceTimersByTime(500)
Expand Down Expand Up @@ -137,7 +138,7 @@ test.skip("component should recreate reaction if necessary", () => {

// This unit test attempts to replicate that scenario:

resetCleanupScheduleForTests()
registry.finalizeAllImmediately()

// Unfortunately, Jest fake timers don't mock out Date.now, so we fake
// that out in parallel to Jest useFakeTimers
Expand Down Expand Up @@ -166,9 +167,9 @@ test.skip("component should recreate reaction if necessary", () => {
// and _then_ the component commits.

// Force everything to be disposed.
const skip = Math.max(CLEANUP_LEAKED_REACTIONS_AFTER_MILLIS, CLEANUP_TIMER_LOOP_MILLIS)
const skip = Math.max(REGISTRY_FINALIZE_AFTER, REGISTRY_SWEEP_INTERVAL)
fakeNow += skip
forceCleanupTimerToRunNowForTests()
registry.sweep()

// The reaction should have been cleaned up.
expect(countIsObserved).toBeFalsy()
Expand Down
5 changes: 4 additions & 1 deletion packages/mobx-react-lite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { observerBatching } from "./utils/observerBatching"
import { useDeprecated } from "./utils/utils"
import { useObserver as useObserverOriginal } from "./useObserver"
import { enableStaticRendering } from "./staticRendering"
import { observerFinalizationRegistry } from "./utils/observerFinalizationRegistry"

observerBatching(batch)

Expand All @@ -14,7 +15,9 @@ export { Observer } from "./ObserverComponent"
export { useLocalObservable } from "./useLocalObservable"
export { useLocalStore } from "./useLocalStore"
export { useAsObservableSource } from "./useAsObservableSource"
export { resetCleanupScheduleForTests as clearTimers } from "./utils/reactionCleanupTracking"

export { observerFinalizationRegistry as _observerFinalizationRegistry }
export const clearTimes = observerFinalizationRegistry["finalizeAllImmediately"] ?? (() => {})

export function useObserver<T>(fn: () => T, baseComponentName: string = "observed"): T {
if ("production" !== process.env.NODE_ENV) {
Expand Down
Loading