Passing props
Components take props the way elements do. A parent passes values on the tag, and the child declares them as a typed parameter:
{QUESTS.map((quest, i) => ( <QuestEntry name={quest.name} state={quest.state} y={i * ROW_H} />))}const QuestEntry = ({ name, state }: { name: String; state: QuestState }): Component => ( <text x={4} w={{ fill: 8 }} h={ROW_H} text={name} font={Fonts.PLAIN} valign="middle" shadow color={state === QuestState.COMPLETE ? Colors.GREEN : state === QuestState.IN_PROGRESS ? Colors.YELLOW : Colors.RED} options={['Read journal']} optionSubject={name} />);QuestEntry declares no y, yet the call site passes one.
Props that fall through
Section titled “Props that fall through”A prop the component does not declare is applied to its root element. Here
y={i * ROW_H} lands on the <text>. This works for anything the root takes:
geometry, hide, visual props, options, hover, a ref.
<Stat label="Quest points" value={27} y={0} /><Stat label="Quests" value={QUESTS.length} color={Colors.DIM} y={18} />- The caller wins. A caller’s
w={100}overrides the root’s ownw="fill". - A root that is another component passes the props on to its own root.
- A position is a pair. A caller that gives
yalone keeps the root’s ownx, so the root must write one, asQuestEntry’sx={4}does.
Naming the props type
Section titled “Naming the props type”A longer props type reads better as an interface. Doc comments show when the prop is hovered in an editor:
interface QuestEntryProps { /** The quest's name, as the journal spells it. */ name: String; state: QuestState;}
const QuestEntry = ({ name, state }: QuestEntryProps): Component => { … };Default values
Section titled “Default values”A default makes the prop optional:
const Stat = ({ label, value, color = 0xffffff }: { label: String; value: Int; color?: Int;}): Component => (A default is a literal: 0, -1, '', 0xffffff.
Prop types
Section titled “Prop types”Give a prop the game type it holds, not Int:
interface IconProps { icon: Sprite;}Types lists them all. A record you declared is a prop type too; see Data.
Markup as a prop
Section titled “Markup as a prop”Markup between the tags arrives as the children prop:
<SunkenBox> <layer ref={list} x={2} y={2} w={{ fill: 22 }} h={{ fill: 4 }} scrollHeight={QUESTS.length * ROW_H}> {/* … the rows … */} </layer></SunkenBox>Composing components covers it.
Props are read-only
Section titled “Props are read-only”Compute from props rather than assigning to them. A value that changes over time is state.
const QuestEntry = ({ name, state }: QuestEntryProps): Component => { state = QuestState.COMPLETE; // no const label = state === QuestState.COMPLETE ? name : `${name} …`; // yes …};Clicks on a component
Section titled “Clicks on a component”A component does not take a handler as a prop. Put the handler on a <layer>
around the call:
<layer x={i * 79} y={0} w={74} h={22} onClick={() => { setTab(i); }}>