fix(theme): remove stale React Compiler memo wrappers from theme hooks

Rebase on current main (includes #589 reconciler fix).

The React Compiler memo caches (_c) in useTheme() and usePreviewTheme()
use referential equality checks on destructured context values. These
caches can return stale references when the ThemeProvider's useMemo
recreates the context value object but the individual property
references (setThemeSetting, setPreviewTheme, etc.) compare equal —
the memo short-circuits and returns a cached tuple/object that still
holds the old closure captures.

This is a distinct bug from #589 (which fixed the ink reconciler's
commitUpdate path for host prop updates). #589 ensures that when
React _does_ re-render a component with new props, those props actually
reach the DOM node. But the memo wrappers here prevent React from
_even seeing_ the new context value in the first place — the hook
returns the stale cached result.

Removing the memo wrappers ensures useTheme() and usePreviewTheme()
always read the current context value, eliminating the stale-reference
path entirely.
This commit is contained in:
root
2026-04-12 07:39:39 +00:00
parent 4c50977f3c
commit 2f4a06dd40

View File

@@ -1,4 +1,3 @@
import { c as _c } from "react-compiler-runtime";
import { feature } from 'bun:bundle';
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
import useStdin from '../../ink/hooks/use-stdin.js';
@@ -120,21 +119,8 @@ export function ThemeProvider({
* accepts any ThemeSetting (including 'auto').
*/
export function useTheme() {
const $ = _c(3);
const {
currentTheme,
setThemeSetting
} = useContext(ThemeContext);
let t0;
if ($[0] !== currentTheme || $[1] !== setThemeSetting) {
t0 = [currentTheme, setThemeSetting];
$[0] = currentTheme;
$[1] = setThemeSetting;
$[2] = t0;
} else {
t0 = $[2];
}
return t0;
const { currentTheme, setThemeSetting } = useContext(ThemeContext);
return [currentTheme, setThemeSetting] as const;
}
/**
@@ -145,25 +131,10 @@ export function useThemeSetting() {
return useContext(ThemeContext).themeSetting;
}
export function usePreviewTheme() {
const $ = _c(4);
const {
const { setPreviewTheme, savePreview, cancelPreview } = useContext(ThemeContext);
return {
setPreviewTheme,
savePreview,
cancelPreview
} = useContext(ThemeContext);
let t0;
if ($[0] !== cancelPreview || $[1] !== savePreview || $[2] !== setPreviewTheme) {
t0 = {
setPreviewTheme,
savePreview,
cancelPreview
};
$[0] = cancelPreview;
$[1] = savePreview;
$[2] = setPreviewTheme;
$[3] = t0;
} else {
t0 = $[3];
}
return t0;
cancelPreview,
};
}