AppWorks School Batch #16 Front-End Class 學習筆記&心得(Week 4)

--

(本文所有內容禁止媒體引用)

遠距教學的最後一週,重點來到了前端函式庫「React」,這也是駐點教學後做專案開發的主要工具,過去幾週學的 HTML、CSS、JavaScript、AJAX 全部都得融會貫通。

取自 AppWorks School 前端班課程大綱

進度安排

本週的重頭戲是 React ,在 React 中會大量使用 JavaScript 中回呼函式(callback function)、class 與進階的陣列原型方法,雖然說單純使用 HTML、CSS 與 JavaScript 就可以做出可與使用者互動的網站,但 React 可以將網頁不同區塊各自獨立為元件(component),避免要在多個網頁要處理相同功能時,還得在所有頁面進行重複工作,只要拉出單一元件修改,就可套用於所有使用該元件的頁面。

這也是最後一週以 Treehouse 上課,雖然可以不退訂閱持續享有權限,但 School 只會代墊第一個月的會費,所有內容要不全部學會、要不就是得找到其他免費或已購買的替代資源供複習,但這些內容只是基本功,駐點後的練習應多會以專案為導向,不再有一邊看一邊跟著做的機會,重點是要能夠在卡關時精準定義問題,並快速找到解決的方案。

回呼函式重點

  1. 功能:將函式 A 當成函式 B 的引數,可確保函式 B 執行完畢後才執行函式 A。
  2. 語法:

語法一:普通函式宣告

function A(){
console.log(“It’s A.”);
}

function B(callback){ //callback為參數,function A()被代為引數
callback(); //執行function A(),顯示"It's A."
}

B(A);

語法二:匿名函式

function B(callback){
callback();
}

B(function(){ //把函式A換為匿名函式,直接當B函式引數
console.log("It's A.");
});

語法三:箭頭函式

function B(callback){
callback();
}

B(() => console.log("It's A.")); //再把函式A改成箭頭函式

3. 延遲執行函式方法:window.setTimeout()window.setInterval()

4. 與 DOM 連結:EventTarget.addEventListener()

JavaScript 重點

  1. 陣列原型方法:Array.prototype.forEach()Array.prototype.map()Array.prototype.filter()Array.prototype.reduce()
  2. class 語法練習
class Person{
constructor(name, height){
this.name = name,
this.height = height
}

showHeight() {
console.log(`${this.name} is ${this.height} cm.`);
}
}

let Emily = new Person("Emily", "165");
Emily.showHeight(); //Emily is 165 cm.

React 重點

  1. Node 套件管理器(node package manager, npm)。
  2. 基本架構與原理:
import React from “react”;         //Top-level API
import ReactDOM from “react-dom”; //react-dom package

function App(){ //用函式製作要顯示的HTML元素
return React.createElement(
“h1”, //HTML標籤
{style:{color:"red"}}, //CSS設定
“This is H1.” //內容
);
};

//在HTML檔案的#root處顯示
ReactDOM.render(React.createElement(App), document.querySelector(“#root”));

3. 用類似 HTML 語法寫 React:JSX (JavaScript XML)。

4. JavaScript 編譯器:Babel.js。

5. React 開發者工具。

6. List、keys(搭配 map() 生成新函式時使用)。

元件(components)

功能:為一小段可重複使用的程式碼,一個網頁由多個 components 組成,每個皆可以獨立修改、維護。

架構一:用函式(function)表示:

import React from “react”;
import ReactDOM from “react-dom”;

function App(){ //函式名稱第一個字母必為大寫
return (
<h1>This is H1.</h1> //HTML標籤
);
};

//也可使用箭頭函式如下:
//const App = () => {
// return(
// <h1>
// This is H1.
// </h1>
// );
//};

//將App()函式製造的component在HTML檔案的#root處顯示
ReactDOM.render(<App />, document.querySelector(“#root”));

架構二:用類別(class)表示:

import React from “react”;
import ReactDOM from “react-dom”;

//建立React.Component的API下的子類別
class App extends React.Component{
render(){ //建立render()方法
return (
<h1>This is H1.</h1> //把內容放在render()方法中
);
}

};

ReactDOM.render(<App />, document.querySelector(“#root”));

組合(composition):將多個小 components 放進大 component 中:

import React from "react";
import ReactDOM from "react-dom";

const App = () => { //母元件
return(

//所有子元件放在一個<span>標籤裡面
<span>
<Header />
<Body/>
</span>
);
};

const Header = () => { //子元件Header內容
return(
<h1>
This is H1.
</h1>
);
};

const Body = () => { //子元件Body內容
return(
<p>
This is paragraph.
</p>
);
};

//最後只要顯示母元件App(),就能帶出子元件Header()與Body()的內容
ReactDOM.render(<App />, document.querySelector("#root"));

Props

功能:連結母元件與子元件,子元件可透過 props 取得在母元件定義的屬性。

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
return( //在母元件定義props屬性,修改母元件內容即影響子元件顯示結果
<span>
<Header title="This is header."/>
<Body number={50}/>
</span>
);
};

const Header = (props) => { //子元件取props為參數
return(
<h1>{props.title}</h1> //取得props當中的title屬性
);
};

const Body = (props) => { //子元件取props為參數
return(
<p>{props.number}</p> //取得props當中的number屬性
);
};

ReactDOM.render(<App />, document.querySelector("#root"));

State

功能:子元件狀態不再被母元件綁定,可直接在子元件處理,提高動態感與互動性,但不可直接更改 state,而是要建立新的副本表示更新後的 state。

類別:application state(所有元件都可取得)、component state(僅單一元件可取得)。

使用 class component 改變 state:先在 class component 中,用 this 建立子元件與母元件的關係:

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
return(
<span>
<Header title="This is header."/>
{/* 更改此處Body的數字仍將影響顯示結果 */}
<Body number={10}/>
</span>
);
};

const Header = (props) => {
return(
<h1>{props.title}</h1>
);
};

//props不再透過引數跟母元件連結,而是直接為Body元件自己的屬性
class Body extends React.Component{
render(){
return(
<p>{this.props.number}</p> //新增一個this
)
}
}

ReactDOM.render(<App />, document.querySelector("#root"));

建立 state,子元件的狀態改在子元件設定,原在母元件的設定移除:

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
return(
<span>
<Header title="This is header."/>
{/* 移除在母元件的設定 */}
<Body />
</span>
);
};

const Header = (props) => {
return(
<h1>{props.title}</h1>
);
};

class Body extends React.Component{
//用constructor()建立state
constructor(){
super()
this.state = {
number:500
}
}

// 更常見的state寫法
// state = {
// number:500
// }

render(){
//從props以母元件設定狀態,變成直接在類別中的state設定
return(
<p>{this.state.number}</p> //props改成state
)
}
}

ReactDOM.render(<App />, document.querySelector("#root"));

因應事件調整狀態:

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
return(
<span>
<Header title="This is header."/>
<Body />
</span>
);
};

const Header = (props) => {
return(
<h1>{props.title}</h1>
);
};

class Body extends React.Component{
//原始狀態
state = {
number:500
}

//設定改變狀態的函式
//1. 箭頭函式佳,可直接連結Body元件
//2. 應使用this.setState()改變state
increase = () => {
this.setState({
number: this.state.number + 100
});
}

render(){
return(
<span>
<p>{this.state.number}</p>
{/* 在button多一個onClick觸發increase()事件,箭頭函式佳 */}
<button onClick={() => this.increase()}>add 100</button>
</span>
)
}
}

ReactDOM.render(<App />, document.querySelector("#root"));

使用回呼函式,確保新的 state 會根據前一個 state 調整

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
return(
<span>
<Header title="This is header."/>
<Body />
</span>
);
};

const Header = (props) => {
return(
<h1>{props.title}</h1>
);
};

class Body extends React.Component{

state = {
number:500
}

decrease = () => {
//使用回呼函式,參數設為prevState,確保根據前一個狀態改變state
this.setState( prevState => {
return{
number: prevState.number - 100
}
});
}

render(){
return(
<span>
<p>{this.state.number}</p>
<button onClick={() => this.decrease()}>minus 100</button>
</span>
)
}
}

ReactDOM.render(<App />, document.querySelector("#root"));

補充~使用 function component 改變 state(State Hook):

import React, {useState} from "react";
import ReactDOM from "react-dom";

const Header = () => {
//宣告要改變的內容title與執行改變的setTitle函式
//原本title的state為useState()裡面的內容
let [title,setTitle] = useState("This is H1.");

return(
<span>
{/* 這裡的{title}會在事件觸發後改變 */}
<h1>{title}</h1>
{/* 事件觸發後,執行change函式,函式內容就是新的state */}
<button onClick={() => setTitle("This is Header.")}>Change title</button>
</span>
);
};

ReactDOM.render(<Header />, document.querySelector("#root"));

若將函式內容寫在 return() 內過長,可以改將 return() 內觸發事件後啟動的項目命名為另一函式 changeTitle,函式內容宣告為原 change 函式:

import React, {useState} from "react";
import ReactDOM from "react-dom";

const Header = () => {
let [title,setTitle] = useState("This is H1.");
//changeTitle先被宣告為change函式
const changeTitle = () => {
setTitle("Here is the header");
}

return(
<span>
{/* 這裡的{title}會在事件觸發後改變 */}
<h1>{title}</h1>
{/* 事件觸發後,執行changeTitle */}
<button onClick={changeTitle}>Change title</button>
</span>
);
};

ReactDOM.render(<Header />, document.querySelector("#root"));

心得

React 的操作雖然不像上週的 Express.js 與 AJAX 那麼抽象,使用 JSX 時還跟 HTML 頗為類似,但對於好不容易習慣用 DOM 思考處理事件的我來說,要再適應函式庫中的「prop」與「state」運作模式依然頗為吃力,好不容易懂了 1,作業要求的卻是 1+2+3+4+5,最後雖然那個 1 有順利寫出來,剩下的 2+3+4+5 找了一整天的資料還是沒有頭緒,不管是看文件、Stack Overflow、技術文章、甚至是可以跟著一步一步做的 YouTube 影片、不論語言是中文或英文,常常是投入許多時間還是沒什麼進展。

教學內容沒有完全內化、作業無法準時完成、或完成後還是不知道自己在寫什麼固然有些沮喪,想到駐點後的進度壓力將會更大,總不免有些焦慮,但老師不斷鼓勵我可以先從「模仿」開始,再透過多練習、慢慢抓到感覺,更重要的是知道自己卡在哪裡、可以如何尋找答案,這絕對比由老師直接講解法來得痛苦,但長遠看來,培養「定義問題」、「解決問題」的能力,絕對比當下把作業寫完來得重要。我不時想到在《美國 vs 台灣第一學府!到底差在哪裡?台灣大學這一點超令人羨慕!|The DoDo Men 嘟嘟人》影片中,資工系的陳縕儂老師提到「高等教育應該要以學生自己找答案為主、而非只靠課堂所學完成作業」這個觀點,就會更有動力繼續面對這些讓我暈頭轉向的程式與電腦科學觀念,能夠在寫作業的過程中刺激思考,其實是很幸福的,況且我也只有這麼一個科目要唸,更不會因為作業寫不好而影響 GPA,能真正把這個技能學起來,才是最要緊的。

不到一週後就要開始駐點集訓,根據 School 官方說法,每週學習時間將由遠距時期每週 20~25 小時、大幅提升為每週 70~75小時,但我在遠距時期就常常用到將近 70 小時,實在不敢想像駐點後的生活。說害怕嗎...確實會因為遠距就常常卡關+本土疫情升溫而有些擔心,但想到能夠到現場跟所有師生一起朝同一個目標前進,又不免有些期待。先前看過不少人想申請 School 卻無緣加入,我能夠如此幸運一次就上,當然更要好好把握這難得的機會,調整好心態,面對接下來的每個挑戰!

參考資料

  1. 什麼是Callback函式 (Callback function)
  2. [JavaScript] 一次搞懂同步與非同步的一切:待會叫你 — 回呼函式(Callback Function)

--

--

北國老虎 | Ralph 拉爾夫🐯​
北國老虎 | Ralph 拉爾夫🐯​

Written by 北國老虎 | Ralph 拉爾夫🐯​

NCCUCS | NTULS | EX-FINLAND TOUR GUIDE | https://linktr.ee/ralphhong5465 | 所有圖文禁止媒體轉載

No responses yet