前情提要:在上一篇現在開始用框架寫網頁 — React,我們學習了如何在 React 使用 JSX 撰寫 Element 呈現出網頁頁面,接下來就會帶著大家將這些 React Element 抽離,建立 React 的核心 — Component,並且處理組件內部的資料。
直接利用上一篇文章的 Codesandbox React 專案,我們會實作做一個簡單的計數器。在上篇文章的最後,提到 index.js 裡面的 <App />
就是一個 Component,組件的內容就實作在 app.js 裡。直接修改 app.js 內部的 React Element,呈現出計數器的畫面:
App.js
export default function App() {
return (
<div className="App">
<h1>Member Score</h1>
<div className="member">
<h2>May</h2>
<h3>0</h3>
<button>Plus</button>
<button>Minus</button>
</div>
</div>
);
}
組件的內容被包裹在函式內部,這被稱作是 Function Component。在 index.js 引入在別份程式碼 export
的 Component 後,就會接收它所回傳的 React Element 渲染在網頁上。
接著可以將記錄成員的資料和計數器的網頁元素抽離,新增 Member.js ,拆離上面的 member
區塊變成一個新的 Component。
Member.js
export default function Member() {
return (
<div className="member">
<h2>May</h2>
<h3>0</h3>
<button>Plus</button>
<button>Minus</button>
</div>
);
}
拆離 Component 並且將它 export
後,要做的事就是在 app.js 引入它。
import Member from "./Member";
export default function App() {
return (
<div className="App">
<h1>Member Score</h1>
<!-- 由使用者定義 component 的 element -->
<Member />
</div>
);
}
我們可以隨意將網頁內容劃分成無數個 Component,不過仍然要遵守拆解的原則,讓 Component 只會負責處理與該組件有關的事情。另外你還可以將 Component 拆成更小 Component,比如 Member 內的計數器,就能抽離成 Counter Component。
Counter.js
export default function Counter() {
return (
<div className="counter">
<h3>0</h3>
<button>Plus</button>
<button>minus</button>
</div>
);
}
Member.js
import Counter from "./Counter";
export default function Member() {
return (
<div className="member">
<h2>May</h2>
<Counter />
</div>
);
}
介面組件化的優點之一就是提升重複使用性,比如現在想要有三位成員的分數資料,只要複製三個 <Member />
組件,就可以呈現出同樣的畫面,但同時三個組件會是獨立的,擁有各自的組件資料。
App.js
export default function App() {
return (
<div className="App">
<h1>Member Score</h1>
<Member />
<Member />
<Member />
</div>
);
}
但問題是,現在三個 Component 的名字都是 May,我們希望能夠顯示成員各自的名字。React 就提供一個方法,可以將資料變成物件在 Component 間傳遞,這個物件就被稱作「props」。舉例來說,只要在 <Member />
加上 name='名字'
屬性,{name='名字'}
就會作為 props 傳入到 Member Component 內。
App.js
export default function App() {
return (
<div className="App">
<h1>Member Score</h1>
<Member name='May'/>
<Member name='Selina'/>
<Member name='Julia'/>
</div>
);
}
分別設定好每個組件 props 的值,直接在 Member Component 接收 props 變數使用,就能顯示出各自的名字。
Member.js
import Counter from "./Counter";
export default function Member(props) {
return (
<div className="member">
<h2>props.name</h2>
<Counter />
</div>
);
}
計數器的部分,兩個 Button 可以控制分數的加減,並且要讓Component 能夠記錄並更新分數,我們需要將分數存放到 State 中,當 render()
內部的 State 值更新,React 就會相對地更新網頁內容。
要在 Function Component 使用 State,會使用到 Hook 功能 useState
,它會回傳目前 state 數值,和可以讓你更新 State 的 Function,同時要設定初始值。
Counter.js
import { useState } from "react";
export default function Counter() {
//宣告一個 state 變數 score,初始值為 0
const [score, setScore] = useState(0);
return (
<div className="Counter">
<h3>{score}</h3>
...
</div>
);
}
現在要利用 useState
的 State Function,試著讓 State 隨著我們的輸入來更新。在兩個 Button 分別加上 Click 事件,按下 Plus 就讓計數器的值加一,按下 Minus 就減一:
Counter.js
export default function Counter() {
...
return (
<div className="Counter">
...
<button onClick={() => setScore(score + 1)}>Plus</button>
<button onClick={() => setScore(score - 1)}>minus</button>
</div>
);
}
完成後試著按一按每個成員的計分器,你可以發現每個 Component 就能擁有自己的 State,分別成功記錄每位成員的分數。
大致了解 React 最重要的核心 — Component,我們現在可以自定義網頁元件,並在組件內控制資料的處理。但 React 能做到的不會只有可將網頁介面拆成獨立的組件、提升重用性,下一個章節就再來探討 React 其他更便利的功能,包括條件 Render、生成列表,以及如何提升 Component 的資料層級。
如果文章中有錯誤的地方,要麻煩各位大大不吝賜教;喜歡的話,也要記得幫我按讚訂閱喔❤️