
壹 ❀ 引
按照之前的計划,從這個月開始,我將由淺至深更新一些react相關的技術博文。由於我目前也是react新手一名,所以文章本質上也算自己學習歷程的記錄,倘若這些文章能幫助到一些人那就再好不過了。那么這一篇文章就作為一個新的開端,從零開始一起變得更強吧,本文開始。
貳 ❀ 准備工作
在學習基礎知識之前,我們可以在本地搭建並運行一個react應用,便於后續學習時例子效果預覽。請先確保電腦已成功安裝node.js
。
比如我的學習項目都喜歡丟在D盤,所以可以在D盤新建一個job文件夾(名字隨你喜歡),進入job目錄,打開終端,這里我用的git終端。執行復制npx create-react-app my-app
命令並回車,等待安裝完成。

等到出現Happy hacking!,說明下載完成。

之后就可以看到job目錄下多了一個my-app
文件夾,這就是我們下載的react應用了。雙擊進入my-app目錄,再進入src文件夾,刪除所有文件之后,創建index.css與index.js文件,像這樣:

用編輯器(我用的vscode)打開my-app項目,在前面創建的index.js中拷貝如下代碼:
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
ReactDOM.render(<h1>Hello, world!</h1>, document.getElementById("root"));
注意,由於react的jsx語法特性,我們可以在js中編寫html,所以習慣格式化代碼的同學可能會將代碼格式出問題,畢竟js中無法識別HTML。對於這個問題我們可以通過切換編輯器語言模式來解決,點擊編輯器右下角的語言,如下圖:

輸入java
可以看到下方有個javaScript React
,選擇此語言,再格式化你就發現支持jsx語法了。

每次點擊右下角切換語言也比較麻煩,好的做法是給選擇語言模式直接配置一個鍵盤快捷方式。點擊編輯器左上角的文件--->首選項--->鍵盤快捷方式,之后輸入語言
,可以看到有一個更改語言模式。點擊左邊的修改圖標,輸入你想要的快捷方式,保存即可,這里我用快捷鍵是ctrl+k
,之后就可以通過快捷鍵快速切換語言模式了。

ok,簡單說了下語言模式的事情,現在我們可以通過ctrl+~
打開編輯器的終端,然后輸入npm start
並回車。

你會發現瀏覽器自動打開了一個頁面,這就是我們本地開發環境成功跑起來了。使用本地環境的好處是,我們每次修改並保存代碼,頁面都會自動刷新,而此時頁面赫然顯示了一句 Hello, world!,恭喜你,到這里我們成功創建了第一個屬於自己的應用,雖然它目前還很簡單,但通過后面的學習,我們來一起讓它變得更酷!
叄 ❀ jsx基礎
按照以往傳統的開發習慣,dom結構我們一般寫在html中,而js文件會負責業務相關邏輯,但站在react的角度,我們會在js中編寫html相關代碼,如果你有了解vue的jsx語法,我想你會更快接受這一設定,之前沒了解也不用擔心,我們來解釋下文章開頭代碼做了什么。
讓我們打開項目的public文件,查看index.html
,可以看到代碼中有一個id為root
的div盒子,結合我們前面例子中ReactDOM.render
編譯的內容,其實不難理解,render
只是將需要編譯的dom,塞到了root
的盒子中,這種指定應用容器以及編譯內容的思想其實與vue以及angularjs是相似的,只是現在html換了個地方編寫而已。
jsx屬於JavaScript的語法拓展,事實上它既不是標簽語法,也不是普通字符串(官方稱呼react元素),但它具備JavaScript全部功能。我們編寫的jsx其實會被bable轉譯成React.createElement()
調用(vue也有類似的createElement
方法),比如下面這段代碼是等效的:
const ele = <h1 className="echo">Hello, world!</h1>;
// 等同於
const ele = React.createElement(
"h1", //標簽名
{ className: "echo" }, //標簽屬性
"Hello, world!" //子節點內容
);
而React.createElement()
本質上是創建了一個類似於如下的React對象
,react會讀取並編譯這些對象,用它們構建頁面dom並實時保持更新:
const ele = {
type: 'h1',
props: {
className: 'echo',
children: 'Hello, world!'
}
};
當然這里我們先不用了解的太深,只用知道jsx大致做了什么,以及為什么react中能這么寫就足夠了,它們的轉換過程其實是react元素經過bable轉譯--->React.createElement()
調用--->react對象--->真實dom。而接下來的語法介紹我想大家會十分熟悉。
react元素支持賦予給變量,比如文章開頭的例子也可以寫成這樣:
const ele = <h1>Hello, world!</h1>;
ReactDOM.render(ele, document.getElementById("root"));
當然,react元素支持嵌套,但需要注意的是,如果我們的結構需要換行,官方推薦使用圓括號包裹你的結構,比如:
const ele = (
<div>
<h1>Hello World!</h1>
<h1>My name's echo!</h1>
</div>
);
ReactDOM.render(ele, document.getElementById("root"));
這樣做的好處是能避免代碼壓縮遇到自動插入分號的陷阱。
在vue開發中,我們習慣使用模板語法{{}}
解析變量,表達式,調用方法等等,其實在react中你同樣能這么做,比如:
const myName = "echo";
const add = function (a, b) {
return a + b;
};
const ele = (
<div>
<h1>my name is {myName}</h1>
<h1>{add(2, 2)}</h1>
<h1>{2 + 2}</h1>
</div>
);
ReactDOM.render(ele, document.getElementById("root"));
html標簽有屬性,react元素與標簽一樣,同樣也支持標簽屬性以及自定義,比如下面的例子:
const img = "https://pic.cnblogs.com/avatar/1213309/20200507225901.png";
const ele = (
<div>
<div id="icon">頭像</div>
<img src={img} alt="icon" />
</div>
);
ReactDOM.render(ele, document.getElementById("root"));
這里需要注意的是,不要在{}
外添加引號,如果你需要解析變量,請使用{}
,如果它只是一個字符串,那么請添加引號,二者選其一添加,兩者不要同時使用。
最后,當添加一個jsx結構時只能有一個react根元素,這點與angularjs的自定義指令模板,vue的組件只能有一個根元素情況類似,比如下面這段代碼就是錯誤示范:
const ele = (
<div>1</div>
<div>2</div>
);
正確的做法是為這兩個元素添加一個共有的根元素:
const ele = (
<div>
<div>1</div>
<div>2</div>
</div>
);
但請不要將這些jsx的結構理解成react組件,它們只是一些react元素構成的代碼塊,組件會有專門的方式去創建,這個后面會具體介紹,當然組件也會利用react元素來構建必要的dom結構。
肆 ❀ 元素渲染的不變性
按照我們以往的框架使用經驗,當模板語法解析的某個變量發生改變時,頁面會自動更新這個變量。但在react中,元素渲染都是一次性的,渲染成功后修改變量,頁面並不會有改變,請看下面這個例子:
let num = 0;
setInterval(function () {
num++;
}, 1000);
setInterval(function () {
//控制台輸出num
console.log(num);
}, 1000);
const ele = <div>{num}</div>;
ReactDOM.render(ele, document.getElementById("root"));
打開控制台,你會發現num
在不斷自增,而頁面結構中解析的num
依舊是0,並沒有任何變化,這是因為ReactDOM.render
就是一次性執行,它只會調用了一次,因此沒辦法及時更新num
,比較直接的辦法是可以將render
整個過程也包裹在定時器中,比如:
let num = 0;
setInterval(function () {
num++;
}, 1000);
setInterval(function () {
//利用定時器不斷更新react元素,以及讓render重復渲染
const ele = <div>{num}</div>;
ReactDOM.render(ele, document.getElementById("root"));
}, 1000);
這樣做能達到效果,但直觀感受這種做法並不友好,其實在后續文檔中,react有提供狀態專門用於解決這個問題,當然這都是后話了。
其次,我們雖然用定時器反復執行render
,但神奇的是react在每次更新dom時,對比新舊dom結構,並只更新發生變化的部分,打開瀏覽器控制台,觀察dom變化就非常清楚了。這一點相對我之前使用的angularjs,就非常人性化了...

伍 ❀ 總
那么到這里,我們成功在本地搭建了一個屬於自己的應用,並了解了react中jsx語法,以及一些常見的用法。學習完這些內容,我們可以利用react元素構建出一些簡單的靜態頁面,雖然現在還未涉及組件概念,當然這些將會在后續文章中展開。
不知不覺又凌晨一點了,這篇文章就先寫到這里,那么本文結束。