# 從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)