# React基礎到進階:進階語法概念和生態套件簡介 ###### tags: `React` `前端框架` `心得` `JavaScript` `語法` ## 基礎部分 - [參見前半筆記](https://hackmd.io/@BOBYZH/H1JqsfYg9) ## 進階部分 - 簡介相對複雜、少用的Hooks - 帶過其他React生態圈相關的概念與套件 ### Script - 2:React較複雜的新增概念 較超出純JS概念的部分 - 效能優化與生態圈相關 - Hooks(選用) - **改善效能**選用:類似useEffect的用法 - useCallback(特定函式):裡面的物件不會每次執行時,重複產生內容相同但記憶體位置不同的副本,dependencies放追蹤改變的資料 - 可避免被重新定義,類似函式版的useRef - 但dependencies也可設定重新定義的條件 - useMemo(記憶結果):避免不必要的重複運算,讓dependencies不變時保存既有資料 - 可以和context組合(或改用redux) - 相關語法:React.memo - 存取不受React管理的部分 - useRef使用自製元件的對應語法 - forwardRef:用在外部引入的自製元件(直接用useRef會出錯,表示無法給予ref) - 是一種HOC(high order component) - 自製元件內使用,取代既有的函式型宣告 - 引入時一樣是用useRef - useImperativeHandle:限制父層能存取的範圍 - 在子元件內先用useRef定義變數後,再用useImperativeHandle,定義為forwardRef回傳的數值 - 可讓父層存取定義之外的結果為特定值(如undefined),保護DOM避免直接操作 - 存取已經定義過的Global state - useContext:引入全域共用的資料 - 定義變數後即可使用(推薦解構賦值) - 括號內填入XxxContext即可(即引入的Context模組) - 簡易實現**Flux架構** - useReducer:預先定義state設定規則 - 相當於讓useState資料對應的動作,有不同的方法可用 - 用dispatch的type傳送參數 - 畫面**渲染前**執行 - useLayoutEffect:可先於useEffect變更state,避免閃過初始資料 - **自訂Hooks** - useDebugValue:配合讀取custom hook參數,顯示於console - 可加上第二個參數,改成檢查hook才執行以優化效能 - 相關規則 - 如components放在單獨資料夾 - 裡面也能用既有的React Hooks - 通常也以"useXxx"格式命名 - 可以將多個動作合併在同一個Hooks裡面執行 - 最後回傳的格式類似useState:`[data, method]` - 重複或複雜資料運送推薦使用 - 比class component更高的重用性 - **進階資料狀態管理**: - 元件較多時比props更容易管理 - Flux設計模式/結構:預先定義好規則讓開發者操作 - 內建方案:useContext/Reducer(搭配hooks) - 更全面最有名的狀態管理工具方案:**Redux**([對應Vue的話,類似的是Vuex](https://segmentfault.com/a/1190000039758839)) - 加入store的概念,儲存各類規則(action),與對應的邏輯運算(reducer),再以Provider包覆最外層,提供資料給引入的元件 - 專用hook:useSelector/useDispatch - 衍生的版本與middleware:如[redux-thunk(簡化非同步處理如API串接)](https://blog.csdn.net/CWH0908/article/details/118249011)與[其他套件](https://blog.csdn.net/CWH0908/article/details/118249011) - **路由(Router)** - 也是以狀態管理的概念延伸成頁面的切換 - 有不同的套件方案達成網址隨頁面切換,如React-router-dom - 前端路由套件[常見有**hash VS history mode**的差別](https://www.jianshu.com/p/2b2ed6d83d56)(Vue也有類似的差異) - 如果是RN,常用的對應概念另有Navigator(App沒有網址的變化) - 補充:[不同前後端路由的設計比較](https://iter01.com/556239.html) - **部署** - 因為直接用React寫的不是原生JS,且開發預覽(`npm start`)時用的是node.js,其實是如後端express.js在伺服器上執行 - 除非考慮SSR得部署在伺服器,否則需要編譯成瀏覽器可存取的靜態檔案 - 從框架轉純前端的專案需要打包、編譯等前處理(preprocessing),如create-react-app提供的`npm run build`,再部署build資料夾裡面的檔案,可以靜態網頁的形式運作 - 註:如果想兼具SPA不換頁使用體驗與[SEO的考量](https://progressbar.tw/posts/297),可以改用Next.js等SSR方案(方案不同需部分甚至全面改寫) - 其他 - 元件相關語法 - 引入svg檔案作為元件(`import { ReactComponent as foo } from './foo.svg'`) - 可以將JSX化的HTML放到陣列的變數,變數再於渲染時引入(如`<ul>{liesArray}</ul>`) - 動態載入不常用的元件:`React.lazy()`(使用時才引入)、`<Suspense fallback={<div>讀取狀態</div>}><讀取後顯示的元件/></Suspense>`(試驗功能) - 跳過render,在root以外的地方渲染:`createPortal`(從react-dom而非react引入) - 如果分開渲染的元素結合厚實際有巢狀結構(包住其中一方),仍須注意event Bubbling的情況,不需要冒泡的話元件最外層須加入`event.stopPropagation()`阻擋 - **Progressive Web App(PWA)** - 直接支援的語法:`serviceWorker.unregister()` => `serviceWorker.register()` - 進階功能設定可參考[Mozilla的說明](https://developer.mozilla.org/zh-TW/docs/Web/Progressive_web_apps) - **開發工具**:React Developer Tools(Vue也有類似的) - **瀏覽器預覽的外掛**(新增瑜開發人員工具的頁籤:Components、Profiler) - 可檢視React網頁的格式(如元件關係、狀態等編譯前的原始部分) - 也可以執行效能監控,如重複渲染(re-render)的狀況 - 前端測試:React Testing ## 其他補充 ### 補充1:**React vs Vue** - [從共通Vite編譯談到框架異同之處](https://hackmd.io/@BOBYZH/ryOA_fh75) ### 補充2:**Function Components with Hooks(新) vs Class Components(舊)** - **Hooks概念像是載入已經定義好的功能,需要時「勾在固定位置」即可** - *除了降低使用React的門檻(,也被隔壁新版Vue3~~抄襲~~借鑑*->composition api) - 舊的Class寫法則需要繼承與定義個別階段的功能 - **Class Components需要更多的JS物件導向知識,架構理解與使用上較為複雜** - (尤其是[JS後來ES6才加入的class](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Classes)與繼承、作用域相關的部分) - ES6 class關鍵詞:constructor(宣告屬性)、extends(原型鏈)、this(函式指向)、super(存取父層)、bind(綁定指向)、arrow function(箭頭函式) - 以class定義元件,`constructor()`定義屬性,`render()`的部分也在裡面 - props在`constructor()`與內部呼叫的`super()`填入,再以`this.props`使用資料 - 關於`this`的指向問題,以物件導向模式定義的動作建議接箭頭函式,讓`this`指向為宣告而非呼叫函式的對象(才能正確存取元件內的資料,比每次都用bind方便) - 狀態也是以`this.state.變數名稱`、`this.setState({key: value})`設定 - **不同於Class Components狀態可合併(物件型式),Function Components with Hooks每個state和setState互相獨立** - **比起useEffect hook,setState是用第二個參數填入箭頭函式執行callback** - 細部操作元件的[生命週期函數](https://zh-hant.reactjs.org/docs/react-component.html):依序可在不同「時期」定義動作 - 各項生命週期中,以componentDidMount、componentDidUpdate、component-WillUnmount較為重要 - 如果需要類似memo的API,可以元件繼承改選PureComponent - **如果是初次學習React或寫新的專案,直接學用Function Components即可** - 仍需要接觸已經使用Class Components專案的話,如可以參考[官方的說明](https://zh-hant.reactjs.org/docs/state-and-lifecycle.html),*特別是「生命週期(lifecycle)」的概念比Hooks重要(剛好Vue也有所謂的生命週期)* - 此外,二者的語法不應該混用,即使能運作也可能有非預期錯誤(以及閱讀較混亂)