From 8d2261e06cd6cdaa8af56b69631d2889dfa0f180 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Tue, 27 Oct 2026 04:30:39 -0700 Subject: [PATCH] perf(mobile): worktree setup updates commit the thread screen once useWorktreeSetup copied each new setup snapshot into held state from an effect after commit. LiveThreadRouteController, the route-level controller for the whole thread screen, therefore committed twice for every worktree setup progress update. Hold the snapshot by adjusting state during render instead. React re-runs the hook before committing, and resolveWorktreeSetupSnapshot returns the held object by identity on that pass, so the update settles after one commit. The effect and its set-state-in-effect lint disable go away. Effects: use-worktree-setup.ts 1 -> 0. Co-Authored-By: Claude Opus 5.5 --- apps/mobile/src/features/threads/use-worktree-setup.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/mobile/src/features/threads/use-worktree-setup.ts b/apps/mobile/src/features/threads/use-worktree-setup.ts index cc1c1af091ccb..5972dc7b28180 100644 --- a/apps/mobile/src/features/threads/use-worktree-setup.ts +++ b/apps/mobile/src/features/threads/use-worktree-setup.ts @@ -1,6 +1,6 @@ import type { EnvironmentId, ThreadId, WorktreeSetupSnapshot } from "@t3tools/contracts"; import { resolveVisibleWorktreeSetup } from "@t3tools/client-runtime/worktree-setup"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useEnvironmentQuery } from "../../state/query"; import { vcsEnvironment } from "../../state/vcs"; import { resolveWorktreeSetupSnapshot } from "./worktree-setup-state"; @@ -26,10 +26,10 @@ export function useWorktreeSetup(input: { : null, ); const snapshot = resolveWorktreeSetupSnapshot(input.threadId, query.data, live); - useEffect(() => { - // oxlint-disable-next-line react/set-state-in-effect -- Holds the last setup snapshot while the live subscription changes over. - if (snapshot && snapshot !== live) setHeld({ key, snapshot }); - }, [key, live, snapshot]); + // Hold the newest snapshot so it survives the subscription closing once setup stops running. + // Set during render so each emission commits once; the resolver returns `live` by identity + // on the next pass, which ends the update. + if (snapshot && snapshot !== live) setHeld({ key, snapshot }); return { snapshot, visible: resolveVisibleWorktreeSetup({