# 核心概念

`RJS` 實例（`src/model/RJS.ts`）如何建立與重新渲染，以及每次渲染為何是單次、非響應式。

## 實例生命週期

`"#selector".RJS(body)` 透過 `body.id` 查找目標元素，複製一份作為原始模板（`#model`），並將 `data`／`event`／`when` 儲存於實例上。若選擇器解析結果為 `null`，建構子會提早返回，不會初始化任何實例。

```mermaid
graph TB
    Entry["#selector.RJS(body)"] --> Ctor["建構子: 查找節點, cloneNode(true)"]
    Ctor --> Init["#init()"]
    Init --> Before["when.before_render()"]
    Before -->|"回傳 false"| Cancel["渲染中止"]
    Before -->|"繼續"| SetDOM["#SET_DOM(body, data) — 遞迴走訪"]
    SetDOM --> After["when.rendered()"]
```

`app.renew(body)` 會從複製的 `#model` 還原 DOM（`replaceChildren(...this.#model.children)`），將傳入的 `data`／`event`／`when` 鍵合併進現有實例狀態（未提及的鍵維持原值），並重新執行 `#init()`。這是 `RJS` 實例重新渲染的唯一方式——沒有自動響應式或髒值檢查機制。

`before_render` 回傳 `false` 會中止這次渲染，`rendered` 不會執行，模板文字維持原樣：

```demo
<div id="app"><p>{{ msg }}</p></div>
<script>
    "#app".RJS({
        data: { msg: "rendered" },
        when: {
            before_render: () => {
                console.log("before_render");
                return false;
            },
            rendered: () => console.log("rendered")
        }
    });
    console.log("#app".$.textContent);
</script>
```

## 非響應式是刻意設計

`RJS.ts` 中每一段被註解掉的程式碼（`#dataListener`、`Object.defineProperty` 的 getter/setter 對）都是被移除的響應式 observer 機制。現行設計每次 `#init()` 只渲染一次，需要明確呼叫 `renew()` 才會更新——這項取捨正是 [README](/zh/) 所述「移除自動監聽帶來的效能負擔」。

## 延伸主題

- [指令解析](/zh/core-concepts-directives)：`#SET_DOM` 的指令處理順序與各指令行為
- [文字插值](/zh/core-concepts-interpolation)：`{{ }}` 的取值與輔助函式
