Effects
Transform content into state — markdown, syntax highlighting, async loads.
Some content can't be rendered as primitives until it's transformed: markdown has
to be parsed, code has to be highlighted, a remote value has to load.
useMugenEffect does that transform and stores the result with
useMugenState — and because a set re-measures the row, the
height stays exact the moment the content resolves.
It's shaped like useEffect — (effect, deps), return a cleanup — with one
deliberate difference: it runs for every row, on- or off-screen, not just
mounted ones. That's the point: row 9,000's markdown parses and its height
becomes exact without ever scrolling to it.
Markdown in a row
import {
, , ,
, , ,
} from '@wingleeio/mugen';
interface Post {
: string;
: string;
}
declare function (: string): <string[]>;
function (: Post) {
const [, ] = <string[]>([]);
(() => {
let = false;
(.).(() => {
if (!) ();
});
return () => {
= true;
};
}, [.]);
return (
< ={8} ={16}>
{. === 0 ? (
<>{'Loading…'}</>
) : (
.((, ) => < ={}>{}</>)
)}
</>
);
}
export function ({ }: { : Post[] }) {
const = ({ : });
return (
< ={} ={() => .} ={}
="16px Inter" ={24} ="2xl" />
);
}The row first measures the Loading… placeholder. When parseMarkdown resolves,
setBlocks replaces the blocks, mugen re-walks the row, and the scrollbar grows
to the real, parsed height — no layout shift, no measure-on-mount.
Highlighting code
The same shape — and pair it with useMugenMemo for the cheap synchronous split:
import { , , , , } from '@wingleeio/mugen';
interface Snippet {
: string;
: string;
: string;
}
declare function (: string, : string): <string[]>;
export function (: Snippet) {
// Cheap, synchronous fallback so the first measure is close.
const = (() => ..('\n'), [.]);
const [, ] = <string[] | null>(null);
(() => {
let = false;
(., .).(() => {
if (!) ();
});
return () => {
= true;
};
}, [., .]);
return (
< ={2} ={12}>
{( ?? ).((, ) => (
< ={} ="13px 'JetBrains Mono'" ={20}>
{}
</>
))}
</>
);
}Rules of thumb
- Don't put the state you set into
deps— that would loop. Watch the inputs (the source text), not the output. - Effects run off the measure pass on a microtask; a
setre-measures the row. - Cancel async work in the returned cleanup (the
cancelledflag above) — it runs before the next effect and when the row is removed. - Keep
effectidempotent for a givendeps— it may re-run when deps change.