摘要:最佳實踐一個文件一個組件。,這是包含的是無副作用的純函數(shù)式計算狀態(tài)操作的函數(shù)。,的啟動腳本,啟動開發(fā)模式,項目打包,運行單元測試等等。每次代碼推送到之前也會執(zhí)行所有單元測試用例,全部通過才可以繼續(xù)推送。,首次安裝依賴包之后生成的文件。
前段時間 React license 的問題鬧的沸沸揚揚,搞得 React 社區(qū)人心惶惶,好在最終 React 團隊聽取了社區(qū)意見把 license 換成了 MIT。不管 React license 如何,React 都是一個值得好好學習的優(yōu)秀視圖庫。
本項目算不上什么大型項目,但依然按照大型項目的標準采用前端流行的最佳實踐來打造一個有良好代碼質(zhì)量,高性能,高可維護性,模塊化的應用。本項目是基于 react, redux 構建的 2048,此外也使用了近兩年優(yōu)秀的開源工具來提高代碼質(zhì)量,包括 eslint,stylelint,prettier 等等,以及 travis,codecov 等持續(xù)集成,持續(xù)部署等服務來保障代碼質(zhì)量和提高開發(fā)效率。
項目地址,喜歡的話 github 點個 star 支持下吧?
預覽 桌面端 移動端 特性 響應式自適應桌面和移動平臺不同分辨率和尺寸,支持移動平臺瀏覽器觸控操作。下面的動圖模擬了不同分辨率下的顯示效果。實現(xiàn)方式主要是把 css 單位從 px 換成了 vw 和 rem ,各元素的尺寸是按照分辨率來進行縮放的。css 媒體查詢到移動瀏覽器的話,調(diào)整部分組件的位置,隱藏部分不重要的組件,使頁面更加緊湊。
數(shù)據(jù)持久化網(wǎng)頁應用最怕斷電和離線,第一個問題通過 store.subscribe 訂閱 redux 狀態(tài)更新,把狀態(tài)序列化到 localStorage 儲存,即使刷新,斷電,程序奔潰再次打開仍然是最新的狀態(tài),第二個問題借助 chrome 的 PWA 技術,即使斷開網(wǎng)絡仍然可以訪問緩存的資源文件。
Redux 狀態(tài)redux 是一個可預測的 JS 狀態(tài)管理容器,結合 Redux DevTools extension 擴展可以很方便的進行應用狀態(tài)穿梭,對輔助開發(fā)和debug大有裨益。不僅可以查看 redux 保存的狀態(tài),還可以隨時回到到過去某個時刻的狀態(tài)就像時間穿梭機一樣,也看得到 redux 每次 action 的觸發(fā),以及每次觸發(fā)造成的狀態(tài)改動。
評論系統(tǒng)借助 github issue api,使用 github 賬號登錄之后以回復 issue 的方式留言。留言支持 markdown 格式,和 github issue 體驗類似。
PWA在支持 PWA 技術的瀏覽器上(比如較新的 chrome)打開頁面會自動詢問你添加到屏幕,添加過程就像原生應用的安裝一樣。應用添加之后就可以像原生應用一樣離線操作,也可以卸載應用。下圖演示了 PWA 在 chrome 上面的添加過程,添加完成之后桌面會出現(xiàn)添加的應用,即便關閉所有網(wǎng)絡仍然可以像原生應用一樣正常操作。
i18n應用支持多語言,且自動適配瀏覽器語言設置。目前檢測到瀏覽器支持中文優(yōu)先使用中文,否則默認使用英文顯示。需要更多語言支持,編輯 src/utils/i18n.js 的 data 對象,添加對應語言文字即可。
react 最佳實踐一個文件一個組件。
盡量使用無狀態(tài)(Stateless)組件,也就是如果只是寫一個單純展示的組件,不需要組件保存自己的狀態(tài),不需要生命周期方法或者 refs 來操作 DOM 的組件則優(yōu)先使用無狀態(tài)組件,采用函數(shù)的形式。以項目 Tips 組件示例:
import React from "react"; import PropTypes from "prop-types"; import styles from "./tips.scss"; export default function Tips({ title, content }) { return (); } Tips.propTypes = { title: PropTypes.string.isRequired, content: PropTypes.string.isRequired };{title}
{content}
和上面相反,如果你需要組件生命周期方法優(yōu)化組件性能(典型應用,重寫 shouldComponentUpdate 方法),需要組件保存自己的狀態(tài),或者用 refs 操作 DOM,你就需要一個有狀態(tài)組件,采用 es6 class 繼承 React.Component 的寫法。組件示例:
import React from "react"; import PropTypes from "prop-types"; import classnames from "classnames"; import styles from "./cell.scss"; import { isObjEqual } from "../../utils/helpers"; export default class Cell extends React.Component { static propTypes = { value: PropTypes.number.isRequired }; shouldComponentUpdate(nextProps, nextState) { return ( !isObjEqual(nextProps, this.props) || !isObjEqual(nextState, this.state) ); } render() { const { props: { value } } = this; const color = `color-${value}`; return (); } } {value || null}
事件綁定 this 方法。在構造函數(shù)里面綁定一次 this 之后后面就可以正常使用。以 ControlPanel 組件部分代碼示例:
constructor(...args) { super(...args); this.handleMoveUp = this.handleMoveUp.bind(this); this.handleMoveDown = this.handleMoveDown.bind(this); this.handleMoveLeft = this.handleMoveLeft.bind(this); this.handleMoveRight = this.handleMoveRight.bind(this); this.handleKeyUp = this.handleKeyUp.bind(this); this.handleSpeakerClick = this.handleSpeakerClick.bind(this); this.handleUndo = this.handleUndo.bind(this); }
使用 propTypes 屬性進行傳入 prop 的校驗。可以校驗 prop 的類型和是否必需,非必需的 prop 還必需填寫 defaultProps 默認值。以無狀態(tài)組件 Button 的部分代碼示例:
Button.propTypes = { children: PropTypes.oneOfType([PropTypes.node]), onClick: PropTypes.func, size: PropTypes.oneOf(["lg", "md", "sm", "xs"]), type: PropTypes.oneOf([ "default", "primary", "warn", "danger", "success", "royal" ]).isRequired }; Button.defaultProps = { children: "", onClick() {}, size: "md", };
使用 HOC(Higher-Order Components) 代替 mixin。mixin 官方已經(jīng)不推薦使用了,redux 的 connect 方法就是 HOC 的應用。
為了提高應用性能,避免不必要的視圖重繪,在需要的組件使用 shouldComponentUpdate 方法;以組件 Row 示例:
// 如果該行沒有格子需要刷新也沒有組件自己的狀態(tài)刷新, // 則該組件不執(zhí)行 render 方法, // 避免每次別的行數(shù)據(jù)刷新也跟著重新渲染。 shouldComponentUpdate(nextProps, nextState) { return ( !isObjEqual(nextProps, this.props) || !isObjEqual(nextState, this.state) ); }項目結構
本項目是基于 Facebook 官方出品的 create-react-app 腳手架搭建的,reject 后做了適當修改以適配項目需求。
調(diào)整如下webpack 添加 scss 支持。之所以沒有用 CssInJS 的方案是因為這些方案普遍不完美,也考慮到要遵循樣式和結構分離的原則,scss 是目前比較成熟的 css 預處理器,社區(qū)輪子也比較多,開發(fā)起來很方便。推薦學習 scss/sass 教程。添加 sass-loader 到 scss 規(guī)則下面最下面即可。配置代碼
開啟 css module 支持。在大型項目里面組件之間需要盡量解耦,但是 css 類名的全局特性很容易導致意料之外的錯誤。開啟 css module 之后,所有的類名最終都會被一小段 hash 值填充,所以類名也就有一定的唯一性,不容易污染全局的代碼。配置代碼
添加 stylelint 支持。js 代碼已經(jīng)有 eslint (但采用了更流行,校驗更嚴格的 airbnb 規(guī)則) 來檢查代碼,但是樣式代碼也需要保持代碼風格統(tǒng)一,同時校驗規(guī)則一般有社區(qū)的最佳實踐。配置代碼
添加靜態(tài)資源 cdn 支持。由于項目部署在 github page 在國內(nèi)訪問速度不是很理想,所以在可能的情況下盡量減小 js 包的大小對頁面加載速度至關重要。像 ReactDOM 這類較大的 npm 包從打包文件剝離出去采用 CDN 來加載,可顯著減小打包文件的大小。(PS:之所以 CDN 加載比較快,是因為 CDN 提供商在全國各地都建立了緩存服務器,資源就近獲取比自己從 github 獲取快得多,而且一般 CDN 的帶寬也比較充裕)把 React 和 ReactDOM 剝離出去只需要在 html 文件添加 CDN 的 [script 標簽](),同時在 webpack 添加 externals 屬性,該屬性指定代碼 import 該包時直接從全局變量獲取。剝離后打包的 js 文件大小從 278kb 減小到 164 kb。
添加 webpack 代碼壓縮插件。默認的 webpack 配置直接輸出原始的 js,css 代碼,但添加壓縮過后,文件顯著減小(js 文件從 164kb 到 49kb),對于移動瀏覽器來說打開速度得到明顯提升。配置代碼
添加 webpack-bundle-analyzer 插件,通過各模塊包所占打包文件后的比重來分析項目代碼,借此優(yōu)化代碼。比如,React 和 ReactDOM 的剝離就是因為分析后發(fā)現(xiàn)這兩個包所占比重較大。
文件結構
src, 項目源代碼大部分都在這里,主要是 react 組件 js 代碼 和 scss 樣式代碼。次級目錄包含了 jest 單元測試代碼,測試代碼盡量和源代碼挨著,以方便編寫。
assets,主要存放一些全局樣式代碼,icon svg 文件,游戲音效 mp3 文件,圖片等等;
components,存放 react dumb 組件, 每個組件包含在采用首字母大寫的目錄的 index.js 里面,同時該目錄包含該組件用到樣式的 scss 文件,盡量一個目錄包含該組件所需的所有代碼避免污染其他代碼,提高組件復用性。
containers,存放 react smart 組件,該目錄結構和 components 類似,但因為是 smart 組件,所以這里的組件可以操作 redux 的數(shù)據(jù),不用太考慮復用性。
reducers,這是 redux 包含的是無副作用的純函數(shù)式計算狀態(tài)操作的函數(shù)。
utils,包括評論組件初始化,i18n 多語言文件,移動瀏覽器滑動檢測和注冊 ServiceWorker 等等。
index.js,項目入口文件,主要把 react 根組件 渲染到指定 DOM 節(jié)點,并且注冊 ServiceWorker。
store.js,redux store 初始化,同時 store.subscribe 訂閱應用狀態(tài)更新,序列化狀態(tài)存到 localStorage。
public,包括項目的 html 文件,網(wǎng)站 icon favicon 和 PWA manifest 文件。
config,主要包括 webpack 的各種配置文件。
scripts,npm 的啟動腳本,啟動開發(fā)模式,項目打包,運行 jest 單元測試等等。
build,項目打包后的輸出目錄。
screenshots,README 各種圖片的原圖,為了國內(nèi)用戶訪問方便實際上 README 的圖片來自新浪微博的圖床。
.editorconfig,通用的編輯器配置,統(tǒng)一不同編輯器 / IDE 的代碼格式。
.eslintignore,需要 eslint 忽略的文件或者目錄,規(guī)則類似 .gitignore
.travis.yml, 持續(xù)集成腳本,每次提交代碼到 github 之后,測試服務器都會自動運行該腳本執(zhí)行測試用例,并輸出代碼覆蓋率,最后自動部署到 github page。所有狀態(tài)都在項目中 README 的徽章中可見。
package.json,項目基本信息和部分配置都存在這里。常見的內(nèi)容包括項目的各類依賴包,各種啟動腳本,項目 homepage 等等;為了減少根項目的文件數(shù)目,jest,babel,eslint,stylelint 的配置也寫在這里。值得注意的是,項目中引入 husky,在每次代碼 commit 之前都會執(zhí)行 lint-staged,以自動執(zhí)行 prettier 來美化代碼格式。每次代碼推送 到 github 之前也會執(zhí)行所有單元測試用例,全部通過才可以繼續(xù)推送。
yarn.locl,yarn 首次安裝依賴包之后生成的 lock 文件。通過 yarn 來安裝依賴包時,yarn 自動把項目的依賴包(包括依賴包依賴的父級包)固定在指定的版本(包括依賴包安裝的 url 和 hash 值),這樣所有開發(fā)環(huán)境都使用 yarn 來管理項目,不同的機器不同的系統(tǒng)安裝出來包都是一樣的,這樣就避免了之前 npm 的缺陷(版本要求太松或者父級包版本更新等等導致每次安裝出來的依賴版本不一樣)。
技術棧react,組件式構建 UI
redux,管理應用狀態(tài)
babel,把 es2017+ 語法轉成 es5 兼容語法
webpack,代碼熱加載,scss 樣式文件處理,組件編譯打包等等
scss,成熟的 css 預處理器(之所以沒有用 CssInJS 的方案是因為這些方案普遍不完美,也考慮到要遵循樣式和結構分離的原則)
eslint,使用流行的 airbnb 的代碼規(guī)范嚴格約束代碼風格
stylelint,scss 代碼風格檢查
jest,fb 出品的代碼測試框架,snapshot 功能對測試 react 組件 UI 十分方便
Prettier,js 和 scss 代碼格式美化工具
PWA(Progressive Web Apps),借助瀏覽器 service worker 能力,使 web 應用在移動平臺有接近原生應用的能力,可離線使用,接收通知消息等等
運行 & 測試 & 打包因為配置文件用了 es6+ 語法所以要求 node 的版本大于 6.10,同時建議使用 yarn 來管理依賴包。fork 項目之后可以按如下命令操作。
npm i -g yarn # 安裝 yarn git clone git@github.com:<你的名字>/React-2048-game.git cd React-2048-game yarn # 安裝依賴包 yarn start # 開啟調(diào)試模式,啟動后自動打開瀏覽器 http://localhost:3000 yarn test # 自動測試 yarn build # 打包代碼踩坑記錄
在調(diào)煙花動畫的時候發(fā)現(xiàn)沒效果,仔細對比了下 webpack 編譯后的 css 文件發(fā)現(xiàn)所有的 @keyframes 的名字都加了 hash 值(也就是當成普通的局部 css 類名),解決辦法就是在 @keyframes 的名字前面和整個 scss 文件添加偽類 :global,可以參考煙花的 scss 文件,這不是完美的解決辦法(css 類名不再有局部特性),后續(xù)再深挖一下。
css module 用到的 :global 這個不是標準的偽類,所以 stylelint 需要添加配置以忽略這個錯誤。參見 package.json 的 stylelint.rules。
項目地址,喜歡的話 github 點個 star 支持下吧?文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/89005.html
摘要:前端日報精選帶來了什么以及對的解釋專題之亂序第期如何無痛降低面條代碼復雜度道阻且長啊前端面試總結附答案上前端安全知識中文開源許可證教程阮一峰的網(wǎng)絡日志裝飾器讓你的代碼更簡潔掘金什么是函數(shù)眾成翻譯和十分鐘快速入門眾成翻譯設計最佳實 2017-10-12 前端日報 精選 React 16 帶來了什么以及對 Fiber 的解釋JavaScript專題之亂序【第1076期】 如何無痛降低 if...
摘要:要求通過要求數(shù)據(jù)變更函數(shù)使用裝飾或放在函數(shù)中,目的就是讓狀態(tài)的變更根據(jù)可預測性單向數(shù)據(jù)流。同一份數(shù)據(jù)需要響應到多個視圖,且被多個視圖進行變更需要維護全局狀態(tài),并在他們變動時響應到視圖數(shù)據(jù)流變得復雜,組件本身已經(jīng)無法駕馭。今天是 520,這是本系列最后一篇文章,主要涵蓋 React 狀態(tài)管理的相關方案。 前幾篇文章在掘金首發(fā)基本石沉大海, 沒什么閱讀量. 可能是文章篇幅太長了?掘金值太低了? ...
摘要:多端統(tǒng)一開發(fā)框架優(yōu)秀學習資源匯總官方資源項目倉庫官方文檔項目倉庫官方文檔微信小程序官方文檔百度智能小程序官方文檔支付寶小程序官方文檔字節(jié)跳動小程序官方文檔文章教程不敢閱讀包源碼帶你揭秘背后的哲學從到構建適配不同端微信小程序等的應用小程序最 Awesome Taro 多端統(tǒng)一開發(fā)框架 Taro 優(yōu)秀學習資源匯總 showImg(https://segmentfault.com/img/r...
摘要:不過今天我希望能夠更進一步,不僅僅再抱怨現(xiàn)狀,而是從我個人的角度來給出一個逐步深入學習生態(tài)圈的方案。最后,我還是想提到下對于的好的學習方法就是回顧參照各種各樣的代碼庫,學習人家的用法與實踐。 本文翻譯自A-Study-Plan-To-Cure-JavaScript-Fatigue。筆者看到里面的幾張配圖著實漂亮,順手翻譯了一波。本文從屬于筆者的Web Frontend Introduc...
摘要:在線注冊賬號,數(shù)據(jù)存儲于。年了,還不使用的異步控制體系。過度對數(shù)據(jù)模型進行裝飾的結果便是高耦合,這跟我初衷是基于在線存儲數(shù)據(jù)有關。 為什么又是Todo,全世界的初學者都在做todo嗎?可能很多人要問這句話,其實這句話可以等同于: 為什么你做了個云音樂播放器? 為什么你做了個新聞閱讀APP? 為什么你做了個VUE/REACT版本的CNODE? 究其本質(zhì),這幾個應用都是data-map...
閱讀 993·2021-11-23 09:51
閱讀 2708·2021-08-23 09:44
閱讀 669·2019-08-30 15:54
閱讀 1442·2019-08-30 13:53
閱讀 3117·2019-08-29 16:54
閱讀 2535·2019-08-29 16:26
閱讀 1201·2019-08-29 13:04
閱讀 2327·2019-08-26 13:50