# 從Native到React:初學React.js角度的JavaScript「升級」整理
###### tags: `React` `前端框架` `心得` `JavaScript` `語法`
## 前言
- **學習目標:整理React.js(17)作為前端框架,與Native JS相比增加的常用概念**
- 概念建立後,實作的部分再查文件(沒有概念的話,看不懂甚至不知道要查什麼文件)
- *~~因為不喜歡Vue的模板與專有語法,覺得很不JS想跳槽~~*
- 算是給自己看的讀書筆記、重點整理
- 也可以一邊思考新技術是為了解決那些既有問題
- *~~有餘力的話再整理個Vue3的版本~~*
- 簡述React的**特色:用JavaScript的思維與格式處理前端的渲染**
- 主要的HTML內容改寫在.js檔案(雖然實際格式為[JSX](https://zh-hant.reactjs.org/docs/introducing-jsx.html)),甚至CSS也能選用JS管理
- 只需要一個.html檔案,除了`<head>`的設定,`<body>`只需要`<div id="root"></div>`給React渲染用
- 使用[Virtual DOM的概念](https://ithelp.ithome.com.tw/articles/10234155)一次性的渲染,而非每次個別操作DOM
- 多一些非原生的語法(如[render](https://zh-hant.reactjs.org/docs/rendering-elements.html)),*但看起來風格至少很JS(如和Vue相比?)*
- 因為都放在JS處理,有些原生的寫法得改掉(如避免與保留的關鍵字衝突、符合JS的coding style常規)
- 主要參考資料:
- 可先看先前整理的[入門篇筆記](https://hackmd.io/@BOBYZH/B1xoUGw9F)
1. [**React繁體中文官網**](https://zh-hant.reactjs.org)
- 有完整文檔和示範教學,但更適合當文件查詢
- 示範教學因為用的是舊的class component,要跟著做的話較推薦下一本書的範例
2. [**從Hooks開始, 讓你的網頁React起來(2020)**](https://one.ebook.hyread.com.tw/bookDetail.jsp?id=226978)
- 改編自[鐵人賽系列文章](https://ithelp.ithome.com.tw/users/20103315/ironman/2668),有JS基礎就能讀懂
- 以**專案進度逐步引導**用到的React概念(**初學者**推薦)
3. [**React思考模式:從hook入門到開發實戰(2021)**](https://one.ebook.hyread.com.tw/bookDetail.jsp?id=261452)
- 介紹的React功能相對前者較多,且解釋較多運作的原理(需較多先備知識+論述可能較抽象?)
- **補上前一本書最後只是帶到沒有細述的部分**,但因為後半較複雜,初次讀先大概看過即可(**需實作時再查**套件文件比較好用)
4. 之前參與協作React.js與[React Native](https://reactnative.cn/)(RN,[二者簡易轉換心得](https://hackmd.io/@BOBYZH/B1NpYzKlq))專案經驗
- 補充在本文的個人觀點
## 基礎部分
- 以網頁組成三大元素,個別簡易說明在React多了哪些變動
- 如果是RN,**得使用專為RN設計的語法和套件**
- 寫的不是HTML和CSS,容易出現WEB沒有的概念
- 加上兼顧不同平台效果(Android、iOS...)的話還有個別設定
### 基礎安裝設定
- 簡易版(練習,CDN)
- 在HTML引入"react"(核心邏輯)、"react-dom"(操作WEB)、"babel"(編譯使用JSX語法)的`<scrpt>`標籤
- 推薦配合[codepen](https://codepen.io/topic/react/templates)、[jsbin](https://jsbin.com/?html,js,output)、[repl.it](https://replit.com/)等線上簡易IDE使用
- 複雜版(開發,NPM)
- 新建專案時建議用如[Create React App](https://zh-hant.reactjs.org/docs/create-a-new-react-app.html#create-react-app)等工具產生
- 已有基本套件、結構與設定的專案,改起來比較快
- RN:請從[環境建置](https://reactnative.cn/docs/environment-setup)開始
### HTML:寫法的變化(微調的概念?)
寫的其實是JSX而非純HTML(JSX語法其實非React專用,[Vue也可以用](https://staging-cn.vuejs.org/guide/extras/render-function.html#render-functions-jsx))
- **class => className**(與JS保留的關鍵字衝突)
- **表單**(form)如input、textarea、select中value屬性概念的變化
- value
- 在React中,值可以選用狀態(state)管理
- 新屬性**defaultValue**:輸入欄位只有一開始受狀態影響的初始值
- 既有寫法:欄位數值一直受狀態管理(不像純HTML只定義初始值)
- checked
- 可用回傳布林值設定
- **kebab case => camel case**
- 寫法習慣,如在JS寫CSS/RN的style,否則噴錯誤
- 一些原本沒用kebab的也要改camel,如onclick => on**C**lick
- [onClick載入函式的寫法有有區別](https://zh-hant.reactjs.org/docs/handling-events.html)
- html作為特殊資料類型而非字串)(render()使用)
- `"<div></div>"` => `<div></div>`
- **component(元件/組件,格式:`<Component />`或`<Component>...</ Component>`)**
- 大寫開頭,以和一般的HTML作區別
- 除了自己寫,也可以引入套件(再參考文件說明的屬性使用)
- 使用[**Design System (設計系統)](https://5xruby.tw/posts/react-design-systems)**:如Ant Design、Material UI...,比bootstrap更進階的懶人救星(X)
- 最外層一定要包一個Tag
- 僅包覆不含語意的寫法:Fragment(`<></>`)
- **只要大概了解JSX與純HTML的差別部分,以及有component的概念,即使沒學過React才有的JS語法,就能以既有的概念切版,甚至多少看懂functional component 的用途(個人想法)**
- 略懂就能寫React(X)可以協助較簡單的部分(O)
### CSS:格式的選擇性(不一定要大改)
格式可以和純靜態檔案一樣,或加上JS擴充大改
- **主要考量:分拆管理、避免全域衝突...**
- **可考慮用原生CSS以外的工具,以加入更多程式邏輯要素(如嵌套、變數、運算):**
- [常見工具方案與原生寫法的簡易比較](https://segmentfault.com/a/1190000039824670)
- CSS預處理器(CSS preprocessor)
- 如Sass、Less...
- 與原生CSS寫法基本相容
- 需額外設定才能使用
- CSS Modules
- 簡言之,全域和頁面載入各自的CSS
- 說明[可參考這篇](https://ithelp.ithome.com.tw/articles/10279072)
- 增加的功能相對少
- CSS in JS
- 如styled-components、emotion...
- 簡介[可參考這篇](https://juejin.cn/post/6935245880568053791)
- 與原生CSS寫法差異較多
### Script - 1:加入React才有的常見概念
基本符合JS風格下,新增若干概念和語法
- **`render()`**:頁面用JS設定後才一起渲染,而非個別修改DOM
- **key**:辨認同類元件的索引,重複渲染元件時若沒設定會跳警告
- `${}` vs `{}` / `{{}}`
- `${}`:原生語法的[樣板字面值/模版字符串(template literal)](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Template_literals)
- `{}`:填React props帶入的資料,或是條件轉譯的判斷式(表達/表示式,expression,有回傳值的邏輯運算做為顯示資料)
- 例如切換視圖:{currentPage === 'SomePage' && (<Component />)}
- `{{}}`:填寫CSS/Style屬性(作為物件放到前者的概念)
- **function components**
- 語法特點
- 以函式(function)形式定義參數屬性與回傳的HTML內容
- 主要取代2019年前較複雜的class components
- 也替代處理資料與畫面對應變動的原生語法(querySelector或getElementByClass/Id後修改DOM)
- 也有生命週期(lifecycle)的概念(類似Vue)
- 分3(+1)階段:初始化/創建/掛載(mounting)、更新(updating)、移除/銷毀/卸載(unmounting),(以及JS噴錯的Error Handling)
- 在class components比較重要,function components較少直接用到
- (個別週期的細節太多人介紹,自行找幾篇來看即可)
- **props(概念)**
- 引入父層的資料(父傳子)
- 父層資料變動時,子層元件也會重新轉譯(更新資料渲染)
- 如同一般函式,需有引入/回傳相關的值
- 可使用解構賦值來接收(如參數填入`{value}`)
- 如果元件層次較多(二三層以上),甚至有傳給同層甚至父層的需求,有Global state的概念比較方便(類似全域變數?)
- **Context(概念)**
- Global state在React的實作方案
- 建立全域資料:`React.createContext()`
- 產生物件,可獨立成外部模組檔案引用(如放context資料夾)
- 使用全域資料:`<XxxContext.Provider>`
- 以元件形式引入,屬性加上`value={{context檔案的物件資料/動作格式: 要讓全域使用的變數資料/動作名稱}}`(搭配useState)
- 在其他地方使用時,需要使用useContext這個hook
- 數值更新時,有引入的元件會強制渲染(可能影響效能)
- **Hooks(常用)**
- 格式:`useSomething`
- 其實也算JS的函式(function)
- 在元件內處理資料常用:使畫面變更/變更後執行
- 通常不會在迴圈、條件判斷、槽狀結構等「不一定會執行到」的情況使用
- 最常用於資料存取的hooks
- **useState(狀態):定義資料預設內容(`value`)與修改動作**(`setValue`)
- 常以解構賦值定義(如`const [value, setValue] = useState("default")`)
- **代替使用變數`var/let`的原生寫法來管理**
- 檢查到狀態變更後重新渲染DOM
- 資料與畫面需透過`setValue`的形式修改與渲染,否則無效或噴錯誤(不要用原生的變數寫法來處理,可能值改了但畫面沒改)
- 會一次覆蓋全部,只改部分需加入`...value`保留其他資料
- 函式呼叫後其實不會馬上修改state,需要立即接續其他動作的話要用下面的useEffect
- **useEffect(副作用):畫面渲染後才執行的動作**
- 第一個參數,用來定義在畫面更動後的函式,例如:
- 呼叫API存取遠端資料(避免非同步事件阻塞,回傳後再替代載入圖示)
- 外來可能有專門的[suspense](https://reactjs.org/docs/concurrent-mode-suspense.html)來處理
- 使用非React專用的外部函式庫(避免衝突)
- 操作DOM、動畫(避免在前面HTML尚未生成)
- add/removeEventListener(建立時add,第一個參數回傳時remove避免重複監聽)
- set/clearInterval(原理同上)
- 第二個參數,須定義dependencies,可避免陷入更新資料後,又因畫面隨資料變動陷入迴圈(如用空陣列表沒有要觀察的變動)
- 未定義時,元件建立與每次更新都觸發
- 定義空陣列時,元件建立時才觸發
- 若第一個參數的副作用定義區,使用了沒在第二個相依參數的props/state,會有非預期錯誤
- **存取不受React管理的部分**
- useRef:定義的變數可類比直接用原生語法操作DOM元素,而不出現錯誤或React更新渲染
- 括號放預設值,在元件的ref屬性填入使用
- 可用在不需保存狀態的變數、操作特定DOM(新增或移除函式)、用狀態管理可能額外動作的情況(如計數counter、有設定effect副作用)
- 如存放不觸發畫面元件更新的變數
- [和直接定義全域變數的差別:後者會在重新渲染時更新,導致數值不如預期](https://stackoverflow.com/questions/57444154/why-need-useref-and-not-mutable-variable)
- 介於被React管與不管之間(?)
## 進階部分
- [參見後半筆記](https://hackmd.io/@BOBYZH/HJpJHcs-5)