useRef
useRef declares a handle you bind to one component of this render, so other
code can change it, measure it, or bind an event to it. Its module-scope pair
is createRef.
useRef(): RefReference
Section titled “Reference”useRef()
Section titled “useRef()”Call it in a component, then bind it with the ref prop:
export const QuestList = (): Component => { const list = useRef(); <layer ref={list} x={2} y={2} w={{ fill: 22 }} h={{ fill: 4 }} scrollHeight={QUESTS.length * ROW_H}>Parameters
Section titled “Parameters”None.
Returns
Section titled “Returns”A Ref: a handle on one component of this render. A component written twice
has two of them.
Caveats
Section titled “Caveats”- A ref is bound exactly once. Unbound, it addresses nothing (
TS2E215); bound twice in one render, even in different arms, it is refused (TS2E214). - A ref names a component that exists. Read or written above its binding —
in the render body, before the markup — it addresses a component that does
not exist yet, and is refused (
TS2E215). Read it in a handler, in an effect, or in markup below the binding. - A ref you were handed is for reading and writing through, never for
binding.
ref={target}on aRefprop is refused (TS2E230). - A ref write survives an in-place update and not a rebuild. If a change must persist, it is state, not a ref — How updates happen.
const Refused = (): Component => { const plate = useRef(); plate.hide = true; // the rect does not exist yet
return <rect ref={plate} w={52} h={20} color={Colors.WELL} fill />;};Ref fields
Section titled “Ref fields”Writable
Section titled “Writable”Every prop the bound element accepts, by the same name and with the same
meaning: hide, color, text, font, sprite, transparency,
scrollHeight, and so on — the element’s own page lists them. Three groups
are written together, not one at a time:
ref.props = { … }: Several props in one write. Reach for it whenever a single write is refused (TS2E215, “cannot be set through a ref on its own”). The groups:{ x, y }and{ w, h }(geometry with its modes — both axes of a pair, and the values are what markup takes: a number, a keyword,{ right: 4 }, or a conditional);{ item, itemCount, itemCountMode? };{ align, valign, lineHeight };{ offsetX, offsetY, pitch, yaw, roll, zoom }. Any other prop may go inpropstoo, alone or with others:plate.props = { hide: false, x: 'center', y: 0 }.ref.options = [ … ]: The right-click menu, the same value theoptionsprop takes. An assignment writes the slots it names and leaves the rest; the empty list is the clear.ref.onClick = handlerand every other event prop: bind a handler on a component you did not create.= nulltakes it off.
Readable
Section titled “Readable”width,height: The size after layout. Writable too:ref.height = npins the width to its current pixels; to keepfill, writeref.props = { w: 'fill', h: n }.x,y: The position after layout. Writable too:ref.x = npins both axes to pixels; to centre, writeref.props = { x: 'center', y: … }.scrollX,scrollY: The current scroll offset. Writable; assigning moves the scroll, clamped into range.scrollWidth,scrollHeight: The scrollable extent.paramInt(ref),paramText(ref),setParamInt(ref, v),setParamText(ref, v): A per-component value the client keeps for you, read and written by a named parameter.
Every naming of a component reads these, not only a useRef() handle: a
ComponentId parameter (target.width!), event.self, a module-scope
createRef.
onClick={() => { plate.props = { x: "center" }; }} />Giving a child something to change
Section titled “Giving a child something to change”export const Scrollbar = ({ content }: { content: Ref }): Component => { <Scrollbar content={list} />A component cannot take a function; pass the Ref.
Measuring a component
Section titled “Measuring a component” const scrollExtent: Int = content.scrollHeight; const extent: Int = scrollExtent > 0 ? scrollExtent : content.height;A ref you were handed can be read above your own markup.
Reading geometry inside markup
Section titled “Reading geometry inside markup” <text ref={readout} x={0} y={WELL_H + 6} w="fill" h={16} text={`x ${plate.x} · ${plate.width} wide`} font={Fonts.SMALL} valign="middle" shadow color={Colors.DIM} />Moving a component with its mode
Section titled “Moving a component with its mode” if (mode === 0) { target.props = { x: 'left', y: 'center' }; } if (mode === 1) { target.props = { x: 'center', y: 'center' }; } if (mode === 2) { target.props = { x: 'right', y: 'center' }; }Nudging by pixels
Section titled “Nudging by pixels” event.self.x = event.self.x + 8;Writing the menu
Section titled “Writing the menu” if (mode === 2) { target.options = []; } else { target.options = ['Nudge right']; }Binding an event on something you were handed
Section titled “Binding an event on something you were handed” content.onScrollWheel = (event) => { content.scrollY = content.scrollY + event.mouseY * WHEEL; trackScroll(gutter, thumb, capTop, capBottom, content); };Naming a hook’s host
Section titled “Naming a hook’s host” useInterval(() => { setTicks(ticks + 1); }, { everyMs: 200 }, host);A ref handed to a hook says which component the timer or watch lives on. A hidden host does not run it — Timers.
Troubleshooting
Section titled “Troubleshooting”My ref is never bound
Section titled “My ref is never bound”Every useRef() must have a matching ref={…} in the same component’s
markup. If you meant to hand the ref to a child, the child reads and writes
through it; it does not bind it.
My change is undone a moment later
Section titled “My change is undone a moment later”The component was rebuilt, and ref writes are lost. Either make the value a cell and read it in the markup, or move the conditional into a child so this component updates in place.
x cannot be set through a ref on its own
Section titled “x cannot be set through a ref on its own”Through props, geometry is a pair: ref.props = { x: 'center', y: 'center' }.
To move by pixels and pin, ref.x = n pins both axes.
I cannot read the width above my markup
Section titled “I cannot read the width above my markup”The component does not exist yet. Move the read into the prop that needs it, below the binding, or into a handler.