Skip to content

Referencing components with refs

A ref is a handle to a component. With one, a handler can change, move or measure a component other than the one that was clicked.

Call useRef() to get a ref, and bind it with the ref prop:

src/quest-log.ts2
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}>
{/* … */}
<Scrollbar content={list} />

At module scope, declare a ref with a name:

src/marker.ts2
const plate = createRef('docs-marker:plate');

createRef names one component in the project, and can be exported and named by another interface. Use useRef() in a component drawn several times.

Assigning to a ref’s property changes that component. A position goes through props, as a pair:

src/marker.ts2
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' }; }

{ w, h } is the other pair. ref.x = n nudges by pixels:

src/marker.ts2
onOptionSelect={(event) => {
// …
event.self.x = event.self.x + 8;
report(event.self, readout);

ref.options writes the right-click menu, the same list the options prop takes; [] clears it.

Eight properties can be read as well as written, and give the values after layout:

ref.width, ref.heightthe size after layout
ref.x, ref.ythe position after layout
ref.scrollX, ref.scrollYthe current scroll offset
ref.scrollWidth, ref.scrollHeightthe scrollable extent

The scrollbar sizes its thumb from the list it was handed:

src/chrome.ts2
<sprite ref={thumb} y={ARROW} w="fill"
h={Math.max(
MIN_THUMB,
extent > 0 ? (bar.height - ARROW * 2) * content.height / extent : bar.height - ARROW * 2,
)}

A handler can be assigned through a ref. The scrollbar puts the wheel handler on the list it scrolls, so the player scrolls by pointing at the list:

src/chrome.ts2
content.onScrollWheel = (event) => {
content.scrollY = content.scrollY + event.mouseY * WHEEL;
trackScroll(gutter, thumb, capTop, capBottom, content);
};

content.onScrollWheel = null takes it off again.

A ref is an ordinary value: a component takes one as a prop, a plain function as an argument. A module-scope ref goes down as a constant:

src/marker.ts2
<MoveButton label="Left" mode={0} x={0} target={plate} readout={readout} />

A ref you were handed is for reading and writing through; the component that created it binds it.

When two components need to affect each other, the component that renders both holds the ref and passes it down.

A ref write lasts until the markup sets that prop again. A change that must last is state, read in the markup. The reference has useRef, createRef, and the ref properties under Types.