Temel kavramlar
Eleman ve Görünüş
Bileşenin elemanına ve iç etiketlere erişim: `element`, `ref`, `onRefCreated`; `class`, `attr`, `style` ve `setText`.
Bileşen içinde eleman erişimi (element ve ref)
Her bileşenin gerçek DOM düğümüne element ile ulaşılır; eleman bileşen yaratılırken hazırdır. İç etiketlerden birinin bileşenini tutmak için o etikete ref yazılır: JSX'te ref={this.title} (fonksiyon bileşeninde ref={title}) ya da ref={(c) => …}, JSX'siz yazımda props nesnesinin ref anahtarı.
Not sayfasının düzenleme alanı başlık ve metin alanlarını ref ile tutar. Sayfa açılınca metin alanını içeriğinin yüksekliğine getirir, not yeniyse imleci başlığa koyar; yazdıkça metin alanı büyür. onEdit her değişiklikte çağrılan bir geri çağrı prop'udur:
import { Component } from "@motifx/core";
import type { Note } from "../services/notes";
export class NoteFields extends Component<HTMLDivElement, { note: Note; onEdit?: () => void }> {
title!: Component<HTMLInputElement>;
body!: Component<HTMLTextAreaElement>;
fit() {
this.body.style({ height: "auto" });
this.body.style({ height: `${this.body.element.scrollHeight}px` });
}
override onConfigured() {
this.class.add("editor");
}
override onMounted() {
const { note } = this.props;
this.fit();
if (!note.title && !note.body) this.title.element.focus();
}
override view() {
const { note, onEdit } = this.props;
return (
<>
<input ref={this.title} class="editor__title" placeholder="Adsız" aria-label="Başlık" autocomplete="off" x-model={() => note.title} oninput={() => onEdit?.()} />
<textarea
ref={this.body}
class="editor__body"
rows={1}
placeholder="Yazmaya başlayın…"
aria-label="Metin"
x-model={() => note.body}
oninput={() => {
this.fit();
onEdit?.();
}}
/>
</>
);
}
}
import { Component, ComponentBase, motifComponent, motifFragment } from "@motifx/core";
import type { Note } from "../services/notes";
export class NoteFields extends Component<HTMLDivElement, { note: Note; onEdit?: () => void }> {
static override elementTag = "div";
title!: Component<HTMLInputElement>;
body!: Component<HTMLTextAreaElement>;
fit() {
this.body.style({ height: "auto" });
this.body.style({ height: `${this.body.element.scrollHeight}px` });
}
override onConfigured() {
this.class.add("editor");
}
override onMounted() {
const { note } = this.props;
this.fit();
if (!note.title && !note.body) this.title.element.focus();
}
override view() {
const { note, onEdit } = this.props;
const title = motifComponent("input", {
ref: (field: Component<HTMLInputElement>) => (this.title = field),
initializeComponent: (field: ComponentBase) => {
field.class.add("editor__title");
field.attr.add({ placeholder: "Adsız", "aria-label": "Başlık", autocomplete: "off" });
field.bindings.model(() => note.title, (value: string) => (note.title = value));
field.motif.on("input", () => onEdit?.());
},
});
const body = motifComponent("textarea", {
ref: (field: Component<HTMLTextAreaElement>) => (this.body = field),
initializeComponent: (field: ComponentBase) => {
field.class.add("editor__body");
field.attr.add({ rows: 1, placeholder: "Yazmaya başlayın…", "aria-label": "Metin" });
field.bindings.model(() => note.body, (value: string) => (note.body = value));
field.motif.on("input", () => {
this.fit();
onEdit?.();
});
},
});
return motifFragment({ childs: [title, body] });
}
}
import type { Component } from "@motifx/core";
import type { Note } from "../services/notes";
export function NoteFields(props: { note: Note; onEdit?: () => void }) {
const { note, onEdit } = props;
let title!: Component<HTMLInputElement>;
let body!: Component<HTMLTextAreaElement>;
const fit = () => {
body.style({ height: "auto" });
body.style({ height: `${body.element.scrollHeight}px` });
};
return (
<div
class="editor"
onMounted={() => {
fit();
if (!note.title && !note.body) title.element.focus();
}}
>
<input ref={title} class="editor__title" placeholder="Adsız" aria-label="Başlık" autocomplete="off" x-model={() => note.title} oninput={() => onEdit?.()} />
<textarea
ref={body}
class="editor__body"
rows={1}
placeholder="Yazmaya başlayın…"
aria-label="Metin"
x-model={() => note.body}
oninput={() => {
fit();
onEdit?.();
}}
/>
</div>
);
}
import { Component, ComponentBase, motifComponent } from "@motifx/core";
import type { Note } from "../services/notes";
export function NoteFields(props: { note: Note; onEdit?: () => void }) {
const { note, onEdit } = props;
let title!: Component<HTMLInputElement>;
let body!: Component<HTMLTextAreaElement>;
const fit = () => {
body.style({ height: "auto" });
body.style({ height: `${body.element.scrollHeight}px` });
};
return motifComponent("div", {
class: "editor",
onMounted: () => {
fit();
if (!note.title && !note.body) title.element.focus();
},
initializeComponent: (editor: ComponentBase) => {
const titleField = motifComponent("input", {
ref: (field: Component<HTMLInputElement>) => (title = field),
initializeComponent: (field: ComponentBase) => {
field.class.add("editor__title");
field.attr.add({ placeholder: "Adsız", "aria-label": "Başlık", autocomplete: "off" });
field.bindings.model(() => note.title, (value: string) => (note.title = value));
field.motif.on("input", () => onEdit?.());
},
});
const bodyField = motifComponent("textarea", {
ref: (field: Component<HTMLTextAreaElement>) => (body = field),
initializeComponent: (field: ComponentBase) => {
field.class.add("editor__body");
field.attr.add({ rows: 1, placeholder: "Yazmaya başlayın…", "aria-label": "Metin" });
field.bindings.model(() => note.body, (value: string) => (note.body = value));
field.motif.on("input", () => {
fit();
onEdit?.();
});
},
});
editor.controls.add(titleField, bodyField);
},
});
}
import { motifOptions, type Component } from "@motifx/core";
import type { Note } from "../services/notes";
export const NoteFields = (props: { note: Note; onEdit?: () => void }) => motifOptions({
el: "div",
title: undefined as Component<HTMLInputElement> | undefined,
body: undefined as Component<HTMLTextAreaElement> | undefined,
fit() {
this.body!.style({ height: "auto" });
this.body!.style({ height: `${this.body!.element.scrollHeight}px` });
},
onConfigured() {
this.class.add("editor");
},
onMounted() {
this.fit();
if (!props.note.title && !props.note.body) this.title!.element.focus();
},
view() {
const { note, onEdit } = props;
return (
<>
<input ref={this.title} class="editor__title" placeholder="Adsız" aria-label="Başlık" autocomplete="off" x-model={() => note.title} oninput={() => onEdit?.()} />
<textarea
ref={this.body}
class="editor__body"
rows={1}
placeholder="Yazmaya başlayın…"
aria-label="Metin"
x-model={() => note.body}
oninput={() => {
this.fit();
onEdit?.();
}}
/>
</>
);
},
});
import { Component, ComponentBase, motifComponent, motifFragment, motifOptions } from "@motifx/core";
import type { Note } from "../services/notes";
export const NoteFields = (props: { note: Note; onEdit?: () => void }) => motifOptions({
el: "div",
title: undefined as Component<HTMLInputElement> | undefined,
body: undefined as Component<HTMLTextAreaElement> | undefined,
fit() {
this.body!.style({ height: "auto" });
this.body!.style({ height: `${this.body!.element.scrollHeight}px` });
},
onConfigured() {
this.class.add("editor");
},
onMounted() {
this.fit();
if (!props.note.title && !props.note.body) this.title!.element.focus();
},
view() {
const { note, onEdit } = props;
const title = motifComponent("input", {
ref: (field: Component<HTMLInputElement>) => (this.title = field),
initializeComponent: (field: ComponentBase) => {
field.class.add("editor__title");
field.attr.add({ placeholder: "Adsız", "aria-label": "Başlık", autocomplete: "off" });
field.bindings.model(() => note.title, (value: string) => (note.title = value));
field.motif.on("input", () => onEdit?.());
},
});
const body = motifComponent("textarea", {
ref: (field: Component<HTMLTextAreaElement>) => (this.body = field),
initializeComponent: (field: ComponentBase) => {
field.class.add("editor__body");
field.attr.add({ rows: 1, placeholder: "Yazmaya başlayın…", "aria-label": "Metin" });
field.bindings.model(() => note.body, (value: string) => (note.body = value));
field.motif.on("input", () => {
this.fit();
onEdit?.();
});
},
});
return motifFragment({ childs: [title, body] });
},
});
import { Component } from "@motifx/core";
export class NoteFields extends Component {
static elementTag = "div";
title;
body;
fit() {
this.body.style({ height: "auto" });
this.body.style({ height: `${this.body.element.scrollHeight}px` });
}
onConfigured() {
this.class.add("editor");
}
onMounted() {
const { note } = this.props;
this.fit();
if (!note.title && !note.body) this.title.element.focus();
}
view() {
const { note, onEdit } = this.props;
return (
<>
<input ref={this.title} class="editor__title" placeholder="Adsız" aria-label="Başlık" autocomplete="off" x-model={() => note.title} oninput={() => onEdit?.()} />
<textarea
ref={this.body}
class="editor__body"
rows={1}
placeholder="Yazmaya başlayın…"
aria-label="Metin"
x-model={() => note.body}
oninput={() => {
this.fit();
onEdit?.();
}}
/>
</>
);
}
}
import { Component, motifComponent, motifFragment } from "@motifx/core";
export class NoteFields extends Component {
static elementTag = "div";
title;
body;
fit() {
this.body.style({ height: "auto" });
this.body.style({ height: `${this.body.element.scrollHeight}px` });
}
onConfigured() {
this.class.add("editor");
}
onMounted() {
const { note } = this.props;
this.fit();
if (!note.title && !note.body) this.title.element.focus();
}
view() {
const { note, onEdit } = this.props;
const title = motifComponent("input", {
ref: (field) => (this.title = field),
initializeComponent: (field) => {
field.class.add("editor__title");
field.attr.add({ placeholder: "Adsız", "aria-label": "Başlık", autocomplete: "off" });
field.bindings.model(() => note.title, (value) => (note.title = value));
field.motif.on("input", () => onEdit?.());
},
});
const body = motifComponent("textarea", {
ref: (field) => (this.body = field),
initializeComponent: (field) => {
field.class.add("editor__body");
field.attr.add({ rows: 1, placeholder: "Yazmaya başlayın…", "aria-label": "Metin" });
field.bindings.model(() => note.body, (value) => (note.body = value));
field.motif.on("input", () => {
this.fit();
onEdit?.();
});
},
});
return motifFragment({ childs: [title, body] });
}
}
export function NoteFields(props) {
const { note, onEdit } = props;
let title;
let body;
const fit = () => {
body.style({ height: "auto" });
body.style({ height: `${body.element.scrollHeight}px` });
};
return (
<div
class="editor"
onMounted={() => {
fit();
if (!note.title && !note.body) title.element.focus();
}}
>
<input ref={title} class="editor__title" placeholder="Adsız" aria-label="Başlık" autocomplete="off" x-model={() => note.title} oninput={() => onEdit?.()} />
<textarea
ref={body}
class="editor__body"
rows={1}
placeholder="Yazmaya başlayın…"
aria-label="Metin"
x-model={() => note.body}
oninput={() => {
fit();
onEdit?.();
}}
/>
</div>
);
}
import { motifComponent } from "@motifx/core";
export function NoteFields(props) {
const { note, onEdit } = props;
let title;
let body;
const fit = () => {
body.style({ height: "auto" });
body.style({ height: `${body.element.scrollHeight}px` });
};
return motifComponent("div", {
class: "editor",
onMounted: () => {
fit();
if (!note.title && !note.body) title.element.focus();
},
initializeComponent: (editor) => {
const titleField = motifComponent("input", {
ref: (field) => (title = field),
initializeComponent: (field) => {
field.class.add("editor__title");
field.attr.add({ placeholder: "Adsız", "aria-label": "Başlık", autocomplete: "off" });
field.bindings.model(() => note.title, (value) => (note.title = value));
field.motif.on("input", () => onEdit?.());
},
});
const bodyField = motifComponent("textarea", {
ref: (field) => (body = field),
initializeComponent: (field) => {
field.class.add("editor__body");
field.attr.add({ rows: 1, placeholder: "Yazmaya başlayın…", "aria-label": "Metin" });
field.bindings.model(() => note.body, (value) => (note.body = value));
field.motif.on("input", () => {
fit();
onEdit?.();
});
},
});
editor.controls.add(titleField, bodyField);
},
});
}
import { motifOptions } from "@motifx/core";
export const NoteFields = (props) => motifOptions({
el: "div",
title: undefined,
body: undefined,
fit() {
this.body.style({ height: "auto" });
this.body.style({ height: `${this.body.element.scrollHeight}px` });
},
onConfigured() {
this.class.add("editor");
},
onMounted() {
this.fit();
if (!props.note.title && !props.note.body) this.title.element.focus();
},
view() {
const { note, onEdit } = props;
return (
<>
<input ref={this.title} class="editor__title" placeholder="Adsız" aria-label="Başlık" autocomplete="off" x-model={() => note.title} oninput={() => onEdit?.()} />
<textarea
ref={this.body}
class="editor__body"
rows={1}
placeholder="Yazmaya başlayın…"
aria-label="Metin"
x-model={() => note.body}
oninput={() => {
this.fit();
onEdit?.();
}}
/>
</>
);
},
});
import { motifComponent, motifFragment, motifOptions } from "@motifx/core";
export const NoteFields = (props) => motifOptions({
el: "div",
title: undefined,
body: undefined,
fit() {
this.body.style({ height: "auto" });
this.body.style({ height: `${this.body.element.scrollHeight}px` });
},
onConfigured() {
this.class.add("editor");
},
onMounted() {
this.fit();
if (!props.note.title && !props.note.body) this.title.element.focus();
},
view() {
const { note, onEdit } = props;
const title = motifComponent("input", {
ref: (field) => (this.title = field),
initializeComponent: (field) => {
field.class.add("editor__title");
field.attr.add({ placeholder: "Adsız", "aria-label": "Başlık", autocomplete: "off" });
field.bindings.model(() => note.title, (value) => (note.title = value));
field.motif.on("input", () => onEdit?.());
},
});
const body = motifComponent("textarea", {
ref: (field) => (this.body = field),
initializeComponent: (field) => {
field.class.add("editor__body");
field.attr.add({ rows: 1, placeholder: "Yazmaya başlayın…", "aria-label": "Metin" });
field.bindings.model(() => note.body, (value) => (note.body = value));
field.motif.on("input", () => {
this.fit();
onEdit?.();
});
},
});
return motifFragment({ childs: [title, body] });
},
});
Not sayfası alanları <NoteFields note={note} onEdit={() => this.edited(note)} /> ile yerleştirir.
Not sayfası alanları new NoteFields({ note, onEdit: () => this.edited(note) }) ile yerleştirir.
Not sayfası alanları motifComponent(NoteFields, { note, onEdit: () => this.edited(note) }) ile yerleştirir.
ref={(s) => ...}— geri çağırım biçimi;setiketin bileşenidir (düz DOM etiketinde elemanı saranComponent, bileşen etiketinde bileşen örneği, fonksiyon bileşeninde döndürülen kök). JSX'siz yazımda yalnız bu biçim vardır:motifComponent("input", { ref: (s) => (this.title = s), … })(fonksiyon bileşeninde(title = s)).ref={this.x}/ref={ad}— derleyici hedefi çözer. Hedef bir metot, fonksiyon değerli alan ya da yerel fonksiyonsa etiketin bileşeniyle çağrılır. Bildirilmiş bir alan (değersiz ya da düz değerli) ya da başlangıç değeri olmayan bir değişkense bileşen ona atanır. Derleme anında belirlenemeyen hedeflerde (bildirilmemiş ya da üst sınıftan gelen üye, parametre,props.x, fonksiyon tipli alan, getter) karar çalışma anında verilir: değer fonksiyonsa çağrılır, değilse atanır. İçe aktarılan bir fonksiyonu ref olarak vermek için geri çağırım biçimini yazın:ref={(s) => registerField(s)}.ref={registerField}yazımında üretilen kod içe aktarılan ada bir atama dalı da içerir; geliştirme sunucusunda çalışır, amavite build(Rollup) "Illegal reassignment of import" hatasıyla durur.- İki biçim de düz DOM etiketinde ve bileşen etiketinde aynı anlamdadır;
x-ref(vex:ref)refile aynıdır. ref, etiketin bileşeni kurulurken (build()'den önce) tam bir kez çağrılır ve DOM'a öznitelik olarak yazılmaz. Sınıf ve Options bileşeni etiketinde ref çağrıldığındaprops, etiketin ortak öznitelikleri (class,id…) veoptionsuygulanmıştır. Düz DOM etiketinde ref anındaoptionsve yapıcıya giden öznitelikler ({...p}ile yayılanlar, JSX'siz yazımda nesneye doğrudan konanlar) uygulanmıştır; JSX'te etikete doğrudan yazılan öznitelikler (class,id,placeholder…) ve JSX'siz yazımdainitializeComponentiçinde eklenenler ise build sırasında, ref'ten sonra yazılır. Fonksiyon bileşeni etiketinde ref, fonksiyon kökünü döndürür döndürmez çağrılır. Sınıf bileşeninde ref taban sınıfın yapıcısı içinde çalışır; alt sınıfın gövdesinde tanımlanan alanlar (marker = 'ready') JavaScript gereği yapıcı döndükten sonra kurulur, ref içinde henüz yoktur. Ref, sınıfın kendi alanlarına yazmak yerine bileşeni üst bileşendeki bir alana atamak için kullanılır (ref={(b) => (this.okButton = b)}).- Aynı etikette
refilex-refbirlikte yazılırsa ikisi de kaynaktaki sırayla birer kez çalışır. refbir prop değildir, yalnız verildiği bileşende çalışır: sınıf bileşeninde bileşenin kendisine, fonksiyon bileşeninde döndürülen köke uygulanır. Fonksiyona gidenprops'ta vethis.props'ta yer almaz; bu yüzden{...props}/{...this.props}ile yaymak onu içteki bir bileşene taşımaz.- JSX'siz kurarken de aynıdır:
motifComponent(Setting, { ref: (c) => ... })ref'i bileşenin kendisine (fonksiyon bileşeninde döndürülen köke) uygular; ref fonksiyona gidenprops'ta vethis.props'ta kalmaz. Sınıf biçimindenew Setting({ ref: (c) => ... })de aynıdır; fonksiyon ve Options biçimindenewkullanılmaz,motifComponentkullanılır. - Kural basittir:
refbir fonksiyonsa bileşenle çağrılır ve prop'tan çıkarılır. Sınıf, Options ve düz etikette bir nesneyse bileşen o alana atanır (props.ref): sınıf biçimliSettingiçinconst p = { name: "Arşiv", hint: "", ref: {} }; const s = new Setting(p);sonrasındap.ref === solur. Fonksiyon bileşeninde nesne biçimli ref'e atama yapılmaz; geri çağırım biçimini kullanın. elementmount'tan önce de vardır; içeriği ise bileşen kurulunca gelir. Belgeye bağlı olmayı gerektiren işler (odak, ölçü)onMountediçinde yapılır.
İçteki bir öğeyi dışarıya açmak için ayrı bir prop adı kullanılır (ör. titleRef) ve içteki etiketin ref'inden çağrılır: <input ref={(c) => props.titleRef?.(c)} … />. Dışarıda <NoteFields note={note} titleRef={(c) => (this.title = c)} /> yazılır (fonksiyon bileşeninde title = c). Bileşen etiketine yazılan ref ise bileşenin kendisini verir; fonksiyon bileşeninde bu, döndürülen kök div'dir. ref={props.titleRef} yazımı da çalışır: değer bir fonksiyonsa içteki bileşenle çağrılır.
onRefCreated — ref'lerin ortak kancası
Sınıf bileşeni onRefCreated(sender) metodunu tanımlarsa, view() içindeki her ref={this.x} / ref={ad} hedefine uygulandıktan hemen sonra bu metot çağrılır. sender ref verilen etiketin bileşenidir; hedef alan o anda atanmış, hedef metot çağrılmış olur. Geri çağırım biçimindeki ref={(s) => ...} için çağrılmaz. JSX'siz yazımda ref daima geri çağırım olduğundan bu kanca yalnız JSX'te çalışır.
Düzenleme alanı, her alana ayrı ayrı oninput yazmak yerine dinleyiciyi tek yerde bağlayabilir:
import { Component } from "@motifx/core";
import type { Note } from "../services/notes";
export class NoteFields extends Component<HTMLDivElement, { note: Note; onEdit?: () => void }> {
title!: Component<HTMLInputElement>;
body!: Component<HTMLTextAreaElement>;
override view() {
const { note } = this.props;
return (
<>
<input ref={this.title} class="editor__title" placeholder="Adsız" x-model={() => note.title} />
<textarea ref={this.body} class="editor__body" placeholder="Yazmaya başlayın…" x-model={() => note.body} />
</>
);
}
onRefCreated(field: Component) {
field.motif.on("input", () => this.props.onEdit?.());
}
}
import { Component } from "@motifx/core";
export class NoteFields extends Component {
static elementTag = "div";
title;
body;
view() {
const { note } = this.props;
return (
<>
<input ref={this.title} class="editor__title" placeholder="Adsız" x-model={() => note.title} />
<textarea ref={this.body} class="editor__body" placeholder="Yazmaya başlayın…" x-model={() => note.body} />
</>
);
}
onRefCreated(field) {
field.motif.on("input", () => this.props.onEdit?.());
}
}
Seçtiğiniz yazımda bu kanca çalışmaz; her ref geri çağırım biçimiyle verilir ve ortak iş o geri çağırımın içinde yapılır.
Her ref, etiketin bileşeni oluşturulduğu anda uygulanır; onRefCreated her birinden sonra bir kez çalışır. Düz bir etiketin içindeki etiketler o etiket kurulurken, yani kardeşleri oluşturulduktan sonra oluşturulur; bu yüzden iç içe yazımda sıra kaynaktaki sıradan farklı olabilir: <form><label><input ref={this.title} /></label><textarea ref={this.body} /></form> yazımında önce body, sonra title uygulanır. Kanca, JSX'i yazan sınıfın (view()'ın this'i) üyesidir; ref verilen bileşenin değil. Sınıfın metotlarında ve alanlarındaki (ok fonksiyonları dahil) JSX için çağrılır; fonksiyon bileşenlerinde, modül düzeyindeki JSX'te, sınıf metodunun içindeki function ifadelerinde ve nesne metotlarında çağrılmaz. Options bileşeninin view()'ı da bir nesne metodudur: oradaki ref={this.x} atanır, ama nesneye yazılan onRefCreated üyesi çağrılmaz.
Görünüş: class, attr, style, setText
Bileşenin elemanının sınıfı, öznitelikleri, satır içi stili ve metni bileşenin üzerinden yönetilir.
Yukarıdaki örnekte this.class.add("editor"), field.attr.add({ … }) ve this.body.style({ height: … }) bunlardır.
Yukarıdaki örnekte kök elemana verilen class="editor" (JSX'siz yazımda class: "editor" anahtarı), field.attr.add({ … }) ve body.style({ height: … }) bunlardır.
| Çağrı | Ne yapar |
|---|---|
class.add("a", "b") |
Sınıf ekler. Fonksiyon (() => (note.pinned ? "pinned" : "")) ve { active: () => open() } nesnesi canlıdır; dizi de verilir. |
class.remove("a"), class.remove("**") |
Sınıfı kaldırır; "**" bütün sınıfları ve canlı kaynakları kaldırır. |
class.has("a") |
Elemanda sınıf var mı. |
attr.add({ type: "button", disabled: () => busy }) |
Öznitelik yazar. Fonksiyon değer canlıdır; false, null ve undefined özniteliği kaldırır, true boş değerle yazar. |
attr.remove("disabled"), attr.has("disabled"), attr.get("href") |
Özniteliği kaldırır, varlığını sorar, değerini okur. |
attr.hold({ disabled: true }) |
Değeri bileşenin kendi değerinin üstünde tutar ve serbest bırakılabilir bir nesne döndürür; dispose() anahtarı bileşenin kendi değerine geri verir. |
style({ height: "120px" }), style("color: red") |
Satır içi stili yazar; nesne yalnız verdiği özellikleri değiştirir, metin bütün stili değiştirir. |
style(() => ({ opacity: … })) |
Canlı stil; fonksiyonun okuduğu değer değişince yeniden yazılır. |
setText("Kaydedildi") |
Elemanın metnini değiştirir (textContent); içindeki çocuk düğümler gider. Canlı metin için bindings.text(() => …) kullanılır. |
class, attr ve style elemanı olmayan bileşende bir şey yapmaz: kök bir yorum düğümüdür (bkz. Kök eleman). class.add aynı sınıfı birden çok kaynaktan sayarak tutar; ayrıntılar ve JSX'teki karşılıkları Stil ve Animasyon sayfasındadır.
attr.add bir anahtara yeniden yazınca önceki değer gider; önceki değer bir fonksiyonsa bağı da kalkar. Bir özniteliği bir süreliğine başka bir değerle örtüp sonra bileşenin kendi değerine dönmek için attr.hold vardır: tutma sürerken bileşenin o anahtara yazdıkları elemana ulaşmaz, dispose() çağrılınca anahtar bileşenin o andaki kendi değerine döner. Kuralları Bileşen Kütüphanesi Yazmak sayfasındadır.
Sonraki adım
Bileşeni göstermek, gizlemek, olay dinlemek ve kaynaklarını bırakmak için motif Ad Alanı bölümüne geçin.