昨天後端完成了二隻apiGET /api/asyHi
和 POST /api/echo
,以及用 POSTMAN 發出 request 到後端並得到回應。 同時,也提到可以用 Chrome devTools 來監控網路 request。
create-react-app
建立,我們第一個前端網頁React 是 Facebook 所開發的一個專案,現在能如此風行有很大的原因是開放社群,開發出以React 為基礎/相關的套件,然而之前有暴出 license 的問題,使人想要退出 React。2017/09/25 正式的改成 MIT license,license 的問題得到了解決(參考:為什麼Facebook更改了React.js的授權?、五種開源授權規範的比較 (BSD, Apache, GPL, LGPL, MIT) )
React 是用來建立使用者介面(UI, user interface)的 javascript 程式庫/套件,它讓我們可以用 Component
組成復雜的 UI。看以下官方例子:
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
// Example usage: <ShoppingList name="Mark" />
首先,<ShoppingList/>
就是一個 Component,他是由「像是」 html tag 的 <div/>
、<hi/>
、<ul/>
、<li/>
組成的。怎麼說「像是」,有注意嗎?我們 不是 寫文字的 "<div>...</div>"
,反是直接寫 <div>...</div>
這類 XML-like,這就是 JSX語法
,它是個語法糖衣(Syntatic Sugar),它會被轉譯器(transpiler)轉成 javascript
class ShoppingList extends React.Component {
render() {
return React.createElement(
"div",
{ className: "shopping-list" },
React.createElement(
"h1",
null,
"Shopping List for ",
props.name
),
React.createElement(
"ul",
null,
React.createElement(
"li",
null,
"Instagram"
),
React.createElement(
"li",
null,
"WhatsApp"
),
React.createElement(
"li",
null,
"Oculus"
)
)
);
}
}
React.createElement()
會回傳 React element,它們是組成 React app 最小的區塊,在 React 會維護自己的虛擬 DOM (React DOM),可以想像成如同 HTML DOM tree 一樣,然後 React DOM 會比較 tree 的差異,進而更新 HTML DOM。
React 沒有規定一定要用 JSX 語法,只是推薦使用,畢竟最後還是轉成 javascript
React.createElement()
。
ShoppingList
component 類別接下來,ShoppingList
他是一個 Class
,他繼承 React.Component
,所以就享有 Component
的功能,像是、Props、State 和 生命周期(Lifecycle)。
建立 instance(即 React element) 不是用直接 new ShoppingList()
,而是透過 JSX 語法建立:
<ShoppingList name="Mark" />;
將會轉譯
React.createElement(ShoppingList, { name: "Mark" });
他會把 ShoppingList
class 送入,交給 React 建立 ShoppingList
instance 和遞迴地建立 render()
裡面的所有 <XXX />
。
最後的問題是:誰來用 <ShoppingList name="Mark" />
?誰是 React app 的入口點?
在網頁讀取完後,一般會立刻執行 ReactDOM.render()
,引發進入 React app 的渲染(render),而更新 HTML DOM。 類似下面
<html>
<body>
<div id='root'></div>
<script type="text/javascript">
const element = <ShoppingList name="Mark" />;
ReactDOM.render(element, document.getElementById('root'));
</script>
</body>
</html>
ReactDOM.render()
會渲染 react element 進 HTML DOM 中的 <div id='root' >
容器內,把 React app 和 HTML DOM 串連起來。
轉譯器有很多(見 Transpilers ),較常見的是 babel,它可以把 JSX 語法轉成 javascript。
先等等,為什麼 babel 會知道<ShoppingList name="Mark" />
轉成 React.createElement(ShoppingList, { name: "Mark" })
,React.createElement()
是哪設定的,以後有 MIT.createElement()
可不可以?這是因為在轉譯前有設定 babel 的 preset
,見下圖
preset 選擇 react
,所以 babel 才知道要怎麼轉譯。再存細看一下,還有看到其它的 preset, es20XX 之類的,這表示 babel 可以認得的語法更多更新,都可以轉成更廣範使用/更低階/更原生的 javascript 語法,像是我們用的 ES6 語法中的 Class
,可以用 babel 轉換成 更原生 javascript
這表示 在當代瀏覽器就算沒支援太新的語法,還是可以透過轉譯器轉換成當代支援的 javascript。早期 ES6 語法未被瀏覽器支援前就是如此,開發者使用較方便的語法開發,再轉換成可以支援javascript。
轉譯器也可以說是 編譯器(compiler),因為它的行為就是從一個語言換成另一個語言,就像 C++ 的編譯器一樣把原始碼轉轉二進碼。
經過前一章的解釋有沒有發現,建立一個 React app 很不容易?要準備 component 原始碼、轉譯器、還要連結 React 和 DOM…等,一堆設定會使人怯步。
拜很多大神所賜,我們現在開發 React app 只要專注在 component,其它的有人會幫你設好。我們採用 create-react-app
,這也是 Facebook 的專案,使得 React app 的建立更方便。
create-react-app
建立 hello-react
安裝 create-react-app
指令
sudo npm install -g create-react-app
開一個 hello-react
的資料夾,並移入
mkdir hello-react
cd hello-react
建立 hello-react
的 React app 專案
create-react-app .
會建立以下的檔案
這就是 Node.js 的專案,src
資料夾放的就是前端的 React 程式碼。
執行開發用伺服器
npm start
這時開啟開發伺服器,自動開啟一個網頁 http://localhost:3000/
會看到這結果,就是一個 React app。
create-react-app
幫我們設定了什麼?除了基本的 React app 專案的設定,還設定了一些開發時實用的東西
create-react-app
提供的開發環境當執行 npm start
就可以執行開發伺服器。因為單單只有網頁原始碥是沒法在網頁看到結果,所以執行開發伺服器會進行之前所提的轉譯…等,並自動的開啟 React app 的網頁。
不只如此,當程式碼發生異動時,還會自動重讀網頁
把 .src/App.js
改成如下:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
render() {
const foo = 'foo';
return (
<div className="App">
Hello React
</div>
);
}
}
export default App;
存檔後回到網頁上看,網頁會自動重新整理
也設定了 ESLint,就如同我們在 Day 6 - 一周目- 程式碼品質工具ESLint,照顧程式碼風格 中設定 Node.js 專案的程式碼品質監控。
只是把 ESLint 組態設定放在 package.json
裡的 eslintConfig
。這裡 ESLint 也可以找的到組態設定。
它也幫我們設定可以在 Chrome devTools 裡進行除錯。
打開 Chrome devTools 後,選 Source 頁籤,按下 command + p (Mac) / ctrl + p(windows),輸入 App
過濾找到 App.js 源始碼。接下來你就可以像 VSCode debug 模式一樣下中斷點除錯。記得下完中斷點要重讀網頁才會觸發網頁 javascript 重新執行。
另開啟一個 ternimal 執行 npm run test
,就可以開啟測試監控。它會掃描專案中的所有測式檔案並執行測試,當程式異動時它還會自動重新執行測試。未來我們會在二周目再做說明。
寫好的 React app 透過 npm run build
,就會把原始碼轉譯、打包成少數js檔案,產生 build
資料夾,裡面就是純前端網頁的所有靜態檔案,把它們放在任何網頁伺服器(ex: nginx) 就可以透過瀏覽器讀取。
create-react-app
提供的開發環境不喜歡它提供的開發環境嗎? npm run eject
脫離他的開發環境。
會專案會變成
這就是他的開發環境本來的面貌:用到 Webpack, Babel, ESLint, Jest,和腳本…等。所有的工具都是要安裝、設定才能用在開發環境,對於新手來說超不友善,所以 create-react-app
幫我們省去了不少麻煩,專心開發 React app。
本主題不會脫離 create-react-app
的開發環境,所以不需要執行npm run eject
。
這過程是不可還原的,所以用之前確認清楚。
我自己測試時發現,
create-react-app
在建立 React app 時有開 local git repository,如果沒 commit 的異動檔案,npm run eject
不能運作。
今天我們介紹了 React 和使用在裡面的 JSX 語法,也用 create-react-app
建立了第一個 React app並說明他提供的開發環境。