Skip to content

Commit

Permalink
feat(react): upgrade peer and dev deps to React 19 (#121)
Browse files Browse the repository at this point in the history
  • Loading branch information
bowheart authored Sep 16, 2024
1 parent 32a2e2d commit 586c025
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 175 deletions.
11 changes: 6 additions & 5 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
"@zedux/atoms": "^1.3.0-rc.2"
},
"devDependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@types/react-dom": "^18.0.11",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"@testing-library/react": "^16.0.1",
"@types/react-dom": "^18.3.0",
"react": "^19.0.0-rc-ee1a403a-20240916",
"react-dom": "^19.0.0-rc-ee1a403a-20240916"
},
"exports": {
".": {
Expand Down Expand Up @@ -55,7 +56,7 @@
],
"license": "MIT",
"peerDependencies": {
"react": ">=18.0.0"
"react": ">=19.0.0"
},
"repository": {
"directory": "packages/react",
Expand Down
46 changes: 36 additions & 10 deletions packages/react/src/hooks/useReactComponentId.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
import React, { useId } from 'react'

type MaybeComponent =
| {
displayName?: string
name?: string
}
| undefined

type React19 = {
__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE?: {
A?: {
getOwner?: () => {
type?: MaybeComponent
}
}
}

__SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE?: {
A?: {
getOwner?: () => {
type?: MaybeComponent
}
}
}
}

const react19KeyBase =
'_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE' as const
const clientKey = `__CLIENT${react19KeyBase}` as const
const serverKey = `__SERVER${react19KeyBase}` as const

/**
* Get a unique id for a Zedux hook call. This id is predictable - it should be
* exactly the same every time a given component renders in the same place in
Expand All @@ -8,18 +38,14 @@ import React, { useId } from 'react'
*
* This uses the forbidden React internals object. We only use it to get a
* dev-friendly name for the React component's node in the atom graph. It's fine
* if React changes their internals - we'll fall back to using a generated node
* name.
* if React changes their internals - we'll fall back to the string "rc" ("React
* Component"). We have no need to "warn users they cannot upgrade" 'cause they
* can at the cost of some DX.
*/
export const useReactComponentId = () => {
const component:
| {
displayName?: string
name?: string
}
| undefined = (React as any)
.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?.ReactCurrentOwner
?.current?.type
const component: MaybeComponent = (
(React as React19)[clientKey] || (React as React19)[serverKey]
)?.A?.getOwner?.()?.type

const name = component?.displayName || component?.name || 'rc'

Expand Down
2 changes: 1 addition & 1 deletion packages/react/test/integrations/ecosystem.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
getEcosystem,
} from '@zedux/react'
import React, { useState } from 'react'
import { act } from 'react-dom/test-utils'
import { act } from '@testing-library/react'
import { ecosystem } from '../utils/ecosystem'
import { renderInEcosystem } from '../utils/renderInEcosystem'
import { fireEvent, render } from '@testing-library/react'
Expand Down
10 changes: 1 addition & 9 deletions packages/react/test/integrations/react-context.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ describe('React context', () => {

render() {
if (this.state.error) {
// You can render any custom fallback UI
return <div data-testid="1">{this.state.error}</div>
}

Expand All @@ -136,7 +135,7 @@ describe('React context', () => {
const div = await findByTestId('1')

expect(div.innerHTML).toMatch(/AtomProvider.*requires.*prop/i)
expect(spy).toHaveBeenCalledTimes(3)
expect(spy).toHaveBeenCalledTimes(1)

spy.mockReset()
})
Expand Down Expand Up @@ -209,7 +208,6 @@ describe('React context', () => {

test('useAtomContext() throws an error if 2nd param is true and no instance was provided', async () => {
jest.useFakeTimers()
const mock = mockConsole('error')
const atom1 = atom('1', (id: string) => id)

function Test() {
Expand All @@ -222,11 +220,5 @@ describe('React context', () => {
const pattern = /no atom instance was provided/i

expect(() => renderInEcosystem(<Test />)).toThrowError(pattern)
expect(mock).toHaveBeenNthCalledWith(
1,
expect.objectContaining({
message: expect.stringMatching(pattern),
})
)
})
})
30 changes: 18 additions & 12 deletions packages/react/test/integrations/suspense.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,15 @@ describe('suspense', () => {
const div2 = await findByTestId('error')

expect(div2.innerHTML).toBe('b')
expect(mock).toHaveBeenCalledTimes(3)
expect(mock).toHaveBeenNthCalledWith(
1,
expect.objectContaining({
message: expect.stringMatching(/uncaught 'b'/i),
})
expect(mock).toHaveBeenCalledTimes(1)
expect(mock).toHaveBeenCalledWith(
expect.any(String),
'b',
expect.stringContaining(
'The above error occurred in the <Child> component'
),
expect.any(String),
expect.any(String)
)
})

Expand Down Expand Up @@ -132,12 +135,15 @@ describe('suspense', () => {
const div2 = await findByTestId('error')

expect(div2.innerHTML).toBe('b')
expect(mock).toHaveBeenCalledTimes(3)
expect(mock).toHaveBeenNthCalledWith(
1,
expect.objectContaining({
message: expect.stringMatching(/uncaught 'b'/i),
})
expect(mock).toHaveBeenCalledTimes(1)
expect(mock).toHaveBeenCalledWith(
expect.any(String),
'b',
expect.stringContaining(
'The above error occurred in the <Child> component'
),
expect.any(String),
expect.any(String)
)
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,40 +76,18 @@ exports[`useAtomSelector inline selector that returns a different object referen
"1": {
"dependencies": Map {},
"dependents": Map {
"@@selector-unnamed-0" => {
"callback": undefined,
"createdAt": 123456789,
"flags": 0,
"operation": "get",
},
"@@selector-unnamed-2" => {
"@@selector-unnamed-1" => {
"callback": undefined,
"createdAt": 123456789,
"flags": 0,
"operation": "get",
},
},
"isSelector": undefined,
"refCount": 2,
"weight": 1,
},
"@@selector-unnamed-0": {
"dependencies": Map {
"1" => true,
},
"dependents": Map {
"Test-:r0:" => {
"callback": [Function],
"createdAt": 123456789,
"flags": 2,
"operation": "useAtomSelector",
},
},
"isSelector": true,
"refCount": 1,
"weight": 2,
"weight": 1,
},
"@@selector-unnamed-2": {
"@@selector-unnamed-1": {
"dependencies": Map {
"1" => true,
},
Expand All @@ -133,41 +111,18 @@ exports[`useAtomSelector inline selector that returns a different object referen
"1": {
"dependencies": Map {},
"dependents": Map {
"@@selector-unnamed-0" => {
"callback": undefined,
"createdAt": 123456789,
"flags": 0,
"operation": "get",
},
"@@selector-unnamed-2" => {
"@@selector-unnamed-1" => {
"callback": undefined,
"createdAt": 123456789,
"flags": 0,
"operation": "get",
},
},
"isSelector": undefined,
"refCount": 2,
"weight": 1,
},
"@@selector-unnamed-0": {
"dependencies": Map {
"1" => true,
},
"dependents": Map {
"Test-:r0:" => {
"callback": [Function],
"createdAt": 123456789,
"flags": 2,
"operation": "useAtomSelector",
"task": undefined,
},
},
"isSelector": true,
"refCount": 1,
"weight": 2,
"weight": 1,
},
"@@selector-unnamed-2": {
"@@selector-unnamed-1": {
"dependencies": Map {
"1" => true,
},
Expand Down
31 changes: 4 additions & 27 deletions packages/react/test/units/useAtomSelector.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -440,22 +440,11 @@ describe('useAtomSelector', () => {
const button = await findByTestId('button')
const div = await findByTestId('text')

// TODO: These snapshots are temporarily wrong in StrictMode pre React 19
// (React 18 StrictMode causes a memory leak). Upgrading to React 19 will
// fix them.
expect(ecosystem.selectors.findAll()).toMatchInlineSnapshot(`
{
"@@selector-unnamed-0": SelectorCache {
"@@selector-unnamed-1": SelectorCache {
"args": [],
"id": "@@selector-unnamed-0",
"nextReasons": [],
"prevReasons": [],
"result": 1,
"selectorRef": [Function],
},
"@@selector-unnamed-2": SelectorCache {
"args": [],
"id": "@@selector-unnamed-2",
"id": "@@selector-unnamed-1",
"nextReasons": [],
"prevReasons": [],
"result": 1,
Expand All @@ -474,17 +463,9 @@ describe('useAtomSelector', () => {

expect(ecosystem.selectors.findAll()).toMatchInlineSnapshot(`
{
"@@selector-unnamed-0": SelectorCache {
"@@selector-unnamed-1": SelectorCache {
"args": [],
"id": "@@selector-unnamed-0",
"nextReasons": [],
"prevReasons": [],
"result": 1,
"selectorRef": [Function],
},
"@@selector-unnamed-2": SelectorCache {
"args": [],
"id": "@@selector-unnamed-2",
"id": "@@selector-unnamed-1",
"nextReasons": [],
"prevReasons": [],
"result": 1,
Expand Down Expand Up @@ -552,10 +533,6 @@ describe('useAtomSelector', () => {

expect(div.innerHTML).toBe('1')
expect(renders).toBe(4) // 2 rerenders + 2 for strict mode

// TODO: These snapshots are temporarily wrong in StrictMode pre React 19
// (React 18 StrictMode causes a memory leak). Upgrading to React 19 will
// fix them.
expect(ecosystem._graph.nodes).toMatchSnapshot()

act(() => {
Expand Down
Loading

0 comments on commit 586c025

Please sign in to comment.