學習React框架 - 002 Day 組件生成與參數傳遞
組件
組件這個詞彙,在前端以往的開發歷程中,通常以頁面區分,但不同的頁面上有相同的功能或顯示區塊時,我們可能會重複的寫著相同的程式碼,或是直接copy & past.
隨著框架思維的日益成熟,「組件」這個想法出現,在React Basic一文中,希望React具有可變性、抽象性、組合性、及狀態保持,以幫助開發者分攤日益複雜的需求及邏輯。
希望有一個思維模型能包含這些概念,而在歷史中,Js的代碼遷移由傳統的OOP開發模型,轉換到了Fn的函式開發架構,React組件也經歷過這些過程,Version16以前由oop的模式為主,Version18後,受到了函式的洗禮,所以組件也的型態也簡化成了Fn的樣態。也就是前一天的範例,我們宣告了一個function,讓React透過編譯器babel生成我們想要的頁面區塊。
那React跟Babel又是透過那些方式將這些組件,注入到頁面上呢?
組件組合及生成
function Profile() {
return (
<img
src="https://i.imgur.com/MK3eW3As.jpg"
alt="Katherine Johnson"
/>
);
}
export default function Gallery() {
return (
<section>
<h1>Amazing scientists</h1>
<Profile />
<Profile />
<Profile />
</section>
);
}
WARNING
組件的名稱必須以大寫字母開頭
可以看到我們定義了兩個函式組件,Gallery中又調用了Profile,來形成頁面架構。 React組件經編譯,最後會轉換成下方代碼注入到頁面上。
<section>
<h1>Amazing scientists</h1>
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
</section>
React.createElement
JSX組件在編譯的過程中透過createElement methods,創建出了虛擬DOM抽象。 簡單來說就是每個組件函式都是一層封裝,其實底層還是js的型態。我們會透過Render轉換成真正的Dom並注入DOM樹中。
React.Render
用於將虛擬 DOM 渲染到實際的 DOM 上。
ReactDOM.render() 方法有兩個參數:
第一個參數是需要渲染的虛擬 DOM 元素。 第二個參數是一個 DOM 元素,表示要將虛擬 DOM 渲染到哪個容器中。 例如,以下代碼將一個包含文本「Hello, world!」的 h1 元素渲染到具有 id 屬性為 root 的 DOM 元素中:
//element只是抽象結構
const element = {
type: "h1",
props: {
title: "foo",
children: "Hello",
},
}
ReactDOM.render(element, document.getElementById("root"));
當代碼執行到 ReactDOM.render() 方法時,React 會將虛擬 DOM 轉換為實際的 DOM,並將其插入到 root 元素中。 參考hello2
render簡化版本如下
function render(element, container) {
// 我們將createElement 的 虛擬dom object結構傳下來,若為非文本結構就創造節點
const dom = element.type === "TEXT_ELEMENT"
? document.createTextNode("")
: document.createElement(element.type);
// 將虛擬dom屬性重現
const isProperty = key => key !== "children";
Object.keys(element.props)
.filter(isProperty)
.forEach(name => {
dom[name] = element.props[name];
});
// 輸入點(root)創建出節點
container.appendChild(dom);
//若還有虛擬DOM上還有下一層子結構,則遞迴的調用Render本身,達到層級渲染的DOM
if (element.props.children) {
element.props.children.forEach(child => {
render(child, dom);
});
}
}
// 再封裝一層抽象 將 root 隱式的封裝在 render中
function ReactDOMRender(element, container) {
const root = {
dom: container,
children: []
};
render(element, container);
}
ReactDOM.render = ReactDOMRender;
虛擬DOM
虛擬 DOM(Virtual DOM)是一個程式概念,它將整個網頁以樹狀結構的物件表示,每個節點對應著網頁上的一個 DOM 元素。React 廣泛地使用虛擬 DOM,它可以快速計算出需要更新的部分,只更新這些部分,而不需要重新渲染整個頁面,從而提高性能和效率。
參數傳遞 Props
就如我們可以傳遞參數進入函式一般,組件也接受參數傳遞至內部,但必須透過嚴謹的方式傳遞,每個父組件都可以通過 props 將一些信息傳遞給它的子組件。 Props 可傳遞任何 JavaScript 值,包括物件、數組和函數。
範例中我們可以透過解構將傳遞的props物件中的屬性給全部解構出來。但必須注意這種使用方式,這會傳遞所有的值。
WARNING
- Props.children 是一個特殊的屬性,並非我們定義的由父層傳遞下來的屬性,可視為具有可由其父組件填充的佔位符.
- 當組件需要更改其 props 時,必須傳遞新的值,因為必須維持不可變性!不要在組件中改變props,以免發生不可預期的錯誤!!
結論
我們理解了組件是如何生成,並且透過那些方法實現並渲染在頁面上,如何傳遞參數給下一層的組件,我們必須維持參數的不可變性,以免發生錯誤。 發現還有children屬性,可以更方便的建構出頁面,並且能使用解構的方式,將複雜的物件結構傳遞至下方組件,但必須清楚的明白為何使用,而不是單方面的為了偷懶...