Skip to content

react-native 0.86.2 - #136

Merged
puckey merged 9 commits into
radio-garden:nextfrom
5-stones:chore/react-native-0.86
Aug 19, 2026
Merged

react-native 0.86.2#136
puckey merged 9 commits into
radio-garden:nextfrom
5-stones:chore/react-native-0.86

Conversation

@jspizziri

Copy link
Copy Markdown
Collaborator

No description provided.

puckey added 6 commits August 19, 2026 08:42
The upgrade's declare-then-assign-in-branches form trips swiftformat's
conditionalAssignment rule, so `yarn ci:format:ios` failed and the iOS job
never reached `swift test`.

Restores the `Optional.map` one-liner with the `@Sendable` annotation on the
map closure's return type. Annotating the binding instead does not compile
("type of expression is ambiguous without a type annotation") -- `@Sendable`
is not inferred through `map`, so the annotation has to reach the closure.
Behaviour is identical: strong local, weak capture, nil when nil.
`connectedService?.let { runBlockingOnMain { player.applyOptions(...) } }`
null-checks the service on the JS thread, then re-reads it through the
`player` getter on the main thread, where the getter throws "Player not
initialized" if it has since gone null.

In practice ordering makes that near-unreachable: every write to
connectedService happens on the main Looper, and so does the hopped block,
so the two cannot interleave. This is a clarity change, not a crash fix --
capturing says once what the two reads said twice, and a teardown that does
race the hop now applies to a detached Service instead of throwing into JS.

Not addressed here: connectedService is a plain non-@volatile field written
on main and read from the JS thread in several places, so a stale read is
still possible. That is the real hazard and wants its own fix.

Also replaces the "hop like every other player-touching method here does"
comment with the actual reason this one blocks instead of launching.
The upgrade already fixed the empty browse list by reading `sections`; what
it left behind is a `content.children` fallback that can never run, under a
comment describing the authored payload shape rather than the resolved one.

A resolved page never carries `children` on any implementation: web's
normalizePage destructures it out on every path, and both natives null it
explicitly (BrowserManager.kt copy(children = null), BrowserManager.swift
copying(children: .some(nil))). ADR 0010 states the invariant.

An example is a spec people copy, so it should model the contract it
actually has. Matches example-native's BrowserScreen, which already did.
`Section.children` is non-optional, so the `?? []` around it goes too.
`jest.config.js` gained a `@react-native/jest-preset` dependency to keep its
preset valid, but nothing can run it: jest is not a dependency of any
workspace (the root runner is vitest), `require.resolve('jest')` fails from
example-native, and `yarn test` there exits "command not found: jest". There
are no test files either.

Removes the config, the `test` script and `@types/jest` rather than adding a
dependency to repair a runner that cannot start. Drops 47 packages.

`@types/jest` was load-bearing for typechecking even though jest could not
run: @react-native/typescript-config declares `types: ["jest"]`, so dropping
it alone breaks `yarn workspace example-native types` with TS2688. Pins
`types: []` in the app's tsconfig to match. Nothing in CI covers that script
-- root `yarn types` only spans src/ -- so it is checked by hand.

Also drops the now-dangling `**/jest.config.js` excludes from the root and
build tsconfigs.
Two blocks where prose was restating what a diagnostic says.

SeekCompletionHandler: four lines on a three-line file, half of it what any
Swift-concurrency-literate reader knows. Trimmed to the part that isn't
recoverable -- the consumer. Sendable looks redundant on an already-@mainactor
protocol, and deleting it is only a *warning* at the capture site
(LoadSeekCoordinator.swift:69, #SendableClosureCaptures), so it merges. Kept
because the failure is quiet, not because the rationale was interesting.

CarPlayImageLoader: six lines arguing that @sendable is needed and that a
@mainactor weak capture is safe -- all of it compiler-enforced, so the prose
only front-runs an error you get anyway. Replaced with the one fact no
diagnostic gives you: the annotation belongs on the closure's return type,
and omitting it fails with "type of expression is ambiguous", which never
mentions @sendable. Also drops "// Build URL resolver closure that wraps
BrowserManager", which restates the line under it.
`track-${si}-${i}-${track.title}` puts a mutable value in a React key. The
section and row indices already make it unique, so the title buys no
uniqueness -- what it buys is a key that changes when a title changes at a
fixed position, which unmounts and remounts the row instead of updating it.

Index-based keys survive here because a navigation replaces the whole page;
rows are never spliced or reordered in place. Keying by identity instead is
not an option: getTrackIdentity returns undefined for browsable-only tracks,
which are most of a browse list, and the same track may legally appear twice
on a page (hence sectionContaining's tappedOffset).

The `track-`/`head-`/`tiles-` prefixes stay. They are redundant for
uniqueness today, but `tiles` and `head` both key on bare `si` and only
avoid collision because a section renders one or the other -- the prefix is
what keeps that from being load-bearing.
@puckey
puckey merged commit 6d906a9 into radio-garden:next Aug 19, 2026
5 checks passed
@radio-garden-release

Copy link
Copy Markdown

🎉 This PR is included in version 0.2.0-next.15 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants