🏠 首頁

🏠 首頁

20 個冷門、但很實用的 git 指令:值得你稍微認識一下

如果您曾經瀏覽過 [git 手冊](https://git-scm.com/docs)(或執行 `man git`),那麼您會發現 git 指令比我們每天在用的多很多。很多指令非常強大,可以讓你的生活更輕鬆(有些比較小眾,但知道一下還是不錯)。 > 這篇文章整理了我最喜歡的 20 個冷門 git 功能,您可以使用來改善您的開發流程、給您的同事留下深刻印象、幫助您回答 git 面試問題,最重要的是 - 可以玩得很開心! 原文出處:https://dev.to/lissy93/20-git-commands-you-probably-didnt-know-about-4j4o --- ## Git Web > 執行 [`git instaweb`](https://git-scm.com/docs/git-instaweb) 可以立即瀏覽 gitweb 中的工作存儲庫 Git 有一個內建的[基於網路可視化工具](https://git-scm.com/docs/gitweb) 可以瀏覽本地存儲庫,它允許您通過瀏覽器中的 GUI 查看和管理您的存儲庫。它包含許多有用的功能,包括: - 瀏覽和單步執行修訂並檢查差異、文件內容和元資料 - 可視化查看提交日誌、分支、目錄、文件歷史和附加資料 - 生成提交和存儲庫活動日誌的 RSS 或 Atom 提要 - 搜尋提交、文件、更改和差異 要打開它,只需從您的存儲庫中執行 `git instaweb`。您的瀏覽器應該會彈出並讀取 http://localhost:1234 。如果您沒有安裝 Lighttpd,您可以使用“-d”標誌指定一個備用 Web 伺服器。其他選項可以通過標誌配置(例如 `-p` 用於端口,`-b` 用於打開瀏覽器等),或在 git 配置中的 `[instaweb]` 塊下配置。 還有 `git gui` 命令,它可以打開一個基於 GUI 的 git 應用程式 ![](https://i.ibb.co/0DrmcWG/Screenshot-from-2022-12-17-20-26-30.png) --- ## Git Notes > 使用 [`git notes`](https://git-scm.com/docs/git-notes) 向提交加入額外訊息 有時您需要將其他資料附加到 git 提交(除了更改、訊息、日期時間和作者訊息之外)。 註釋存儲在 .git/refs/notes 中,由於它與提交對像資料是分開的,因此您可以隨時修改與提交關聯的註釋,而無需更改 SHA-1 哈希。 您可以使用 `git log`、使用大多數 git GUI 應用程式或使用 `git notes show` 命令查看筆記。一些 git 主機還在提交視圖中顯示註釋(儘管 [GH 不再顯示註釋](https://github.blog/2010-08-25-git-notes-display/))。 --- ## Git Bisect > 使用 [`git bisect`](https://git-scm.com/docs/git-bisect) 你可以使用二進制搜尋找到引入錯誤的提交 這是最強大又好用的 git 命令之一 - bisect 在除錯時絕對是救命稻草。開始對分後,它會為您檢查提交,然後您告訴它提交是“好”(沒有錯誤)還是“壞”(引入錯誤),這可以讓您縮小最早提交的錯誤。 請執行 `git bisect start`,然後使用 `git bisect good <commit-hash>` 向其傳遞一個已知的良好提交,並使用 `git bisect bad <optional-hash>` 傳遞一個已知的錯誤提交(預設為當前)。然後它會檢查好提交和壞提交之間的提交,然後你用 `git bisect good` 或 `git bisect bad` 指定錯誤存在與否。然後它會重複這個過程,在好與壞的中心檢查一個提交,一直到你找到引入錯誤的確切提交。隨時使用 `git bisect reset` 取消。 bisect 命令還有更多功能,包括回放、查看提交、跳過,因此下次除錯時值得查看文檔。 --- ## Git Grep > 使用 [`git grep`](https://git-scm.com/docs/git-grep) 在您的存儲庫中搜尋程式碼、文件、提交或任何其他內容 有沒有發現自己需要在 git 專案中的任何地方搜尋字串?使用 git grep,您可以輕鬆地在整個專案中和跨分支搜尋任何字串或 RegEx(例如更強大的 <kbd>Ctrl</kbd> + <kbd>F</kbd>!)。 `git grep <regexp> <ref>` 它包括大量 [選項](https://git-scm.com/docs/git-grep#_options) 來縮小搜尋範圍,或指定結果格式。例如,使用 `-l` 僅返回文件名,`-c` 指定每個文件返回的匹配數,`-e` 排除匹配條件的結果,`--and` 指定多個條件,` -n` 以行號搜尋。 由於 git grep 與正則表達式兼容,因此您可以使用搜尋的字串獲得更多進階訊息。 您還可以使用它來指定文件擴展名,例如 `git grep 'console.log' *.js`,它將顯示 JavaScript 文件中的所有 console.logs 第二個參數是一個 ref,可以是分支名稱、提交、提交範圍或其他任何內容。例如。 `git grep "foo" HEAD~1` 將搜尋之前的提交。 --- ## Git Archive > 使用 [`git archive`](https://git-scm.com/docs/git-archive) 將整個 repo 合併到一個文件中 共享或備份存儲庫時,通常首選將其存儲為單個文件。使用 git archive 將包括所有 repo 歷史記錄,因此可以輕鬆將其提取回其原始形式。該命令還包括許多附加選項,因此您可以準確自定義存檔中包含和不包含的文件。 ``` git archive --format=tar --output=./my-archive HEAD ``` --- ## Git Submodules > 使用 [`git submodule`](https://git-scm.com/docs/git-submodule) 將任何其他存儲庫拉入您的存儲庫 在 git 中,[submodules](https://git-scm.com/docs/gitsubmodules) 讓您可以將一個存儲庫掛載到另一個存儲庫中,通常用於核心依賴項或將組件拆分到單獨的存儲庫中。有關詳細訊息,請參閱[這篇文章](https://notes.aliciasykes.com/17996/quick-tip-git-submodules)。 執行以下命令會將模塊拉到指定位置,並建立一個 .gitmodules 文件,以便在複製 repo 時始終下載它。複製 repo 時使用 `--recursive` 標誌來包含子模塊。 ``` git submodule add https://github.com/<user>/<repo> <path/to/save/at> ``` 還有 [`git subtree`](https://www.atlassian.com/git/tutorials/git-subtree),它做類似的事情,但不需要元資料文件。 --- ## Git Bug Report > 使用 [`git bugreport`](https://git-scm.com/docs/git-bugreport) 編寫錯誤票,包括 git 和系統訊息 此命令將捕獲系統訊息,然後打開一個標準錯誤模板(重現步驟、實際 + 預期輸出等)。完成的文件應該是一個非常完整的錯誤報告,包含所有必要的訊息。 如果您是開源包的維護者並要求用戶(開發人員)提出錯誤報告,這將非常方便,因為它確保包含所有必要的資料。 如果您向核心 git 系統提交錯誤報告,您還可以執行 [`git diagnostic`](https://git-scm.com/docs/git-diagnose) 命令,然後提出您的問題 [這裡](https://github.com/git/git)。 --- ## Git Fsck > 使用 [`git fsck`](https://git-scm.com/docs/git-fsck) 檢查所有物件,或恢復無法存取的物件 雖然不常需要,但有時您可能必須驗證 git 存儲的物件。這就是 fsck(或文件系統檢查)發揮作用的地方,它測試對像資料庫並驗證所有物件的 SHA-1 ID 及其建立的連接。 它還可以與 `--unreachable` 標誌一起使用,以查找不再可以從任何命名引用存取的物件(因為與其他命令不同,它包括 `.git/objects` 中的所有內容)。 --- ## Git Stripspace > 使用 [`git stripspace`](https://git-scm.com/docs/git-stripspace) 格式化給定文件中的空格 最佳做法是避免在行尾尾隨空格,避免有多個連續的空行,避免輸入的開頭和結尾出現空行,並以新行結束每個文件。有很多特定於語言的工具可以自動為您執行此操作(例如 prettier),但 Git 也內置了此功能。 它用於元資料(提交訊息、標籤、分支描述等),但如果您將文件通過管道傳輸給它,然後將響應通過管道傳輸回文件,它也可以工作。例如。 `cat ./path-to-file.txt | git stripspace` 或 `git stripspace < dirty-file.txt > clean-file.txt` 您還可以使用它來刪除註釋(使用 `--strip-comments`),甚至註釋掉行(使用 `--comment-lines`)。 --- ## Git Diff > 使用 [`git diff`](https://git-scm.com/docs/git-diff) 你可以比較 2 組程式碼之間的差異 您可能知道您可以執行 `git diff` 來顯示自上次提交以來的所有更改,或者使用 `git diff <commit-sha>` 來比較 2 次提交或 1 次提交到 HEAD。但是您可以使用 diff 命令做更多的事情。 您還可以使用它來比較任意兩個任意文件,使用 `diff file-1.txt file-2.txt`(不再存取 [diffchecker.com](https://www.diffchecker.com/compare/)! ) 或者使用 `git diff branch1..branch2` 相互比較 2 個分支或引用 請注意,雙點 (`..`) 與空格相同,表示 diff 輸入應該是分支的尖端,但您也可以使用三點 (`...`) 來轉換第一個參數進入兩個差異輸入之間共享的共同祖先提交的引用 - 非常有用!如果只想跨分支比較單個文件,只需將文件名作為第三個參數傳遞。 您可能希望查看在給定日期範圍內所做的所有更改,為此使用 `git diff HEAD@{7.day.ago} HEAD@{0}`(上週),同樣可以將其與文件名、分支名稱、特定提交或任何其他參考。 還有 [`git range-diff`](https://www.git-scm.com/docs/git-range-diff) 命令,它提供了一個用於比較提交範圍的簡單界面。 git diff 工具還有更多功能(以及使用您自己的差異檢查器的選項),因此我建議查看 [文檔](https://git-scm.com/docs/git-diff#_description) . --- ## Git Hooks > 使用 [`hooks`](https://git-scm.com/docs/githooks) 在給定的 get 操作發生時執行命令或執行腳本 Hooks 可以讓你自動化幾乎所有的事情。例如:確保滿足標準(提交訊息、分支名稱、補丁大小)、程式碼質量(測試、lint)、將附加訊息附加到提交(用戶、設備、票證 ID)、呼叫 webhook 來記錄事件或執行管道等 對於大多數 git 事件,如 commit, rebase, merge, push, update, applypatch 等,都有前後 [hooks available](https://git-scm.com/docs/githooks)。 鉤子存儲在 `.git/hooks` 中(除非您使用 `git config core.hooksPath` 在其他地方配置它們),並且可以使用 [`git hook`](https://git-scm.com/docs) 進行測試/git-hook) 命令。由於它們只是 shell 文件,因此可用於執行任何命令。 掛鉤不會推送到遠程存儲庫,因此要在您的團隊中共享和管理它們,您需要使用 [掛鉤管理器](https://github.com/aitemr/awesome-git-hooks#tools) ,例如 [lefthook](https://github.com/evilmartians/lefthook) 或 [husky](https://github.com/typicode/husky)。還有幾個[3rd-party tools](https://githooks.com/#projects),這使得管理鉤子更容易,我推薦[overcommit](https://github.com/sds/overcommit)。 請記住,掛鉤總是可以跳過(使用 `--no-verify` 標誌),所以永遠不要純粹依賴掛鉤,尤其是對於任何與安全相關的事情。 --- ## Git Blame > 使用 [`git blame`](https://git-scm.com/docs/git-blame) 顯示特定修訂版和行的作者訊息 一個經典的,快速找出誰寫了特定程式碼行(也就是你的哪個同事應該為這個錯誤負責!)。但它也有助於確定在哪個時間點發生了某些更改並檢查該提交和關聯的元資料。 例如,要查看 index.rs 第 400 到 420 行的作者和提交訊息,您可以執行: ``` git blame -L 400,420 index.rs ``` --- ## Git LFS > 使用 [`git lfs`](https://git-lfs.github.com/) 存儲大文件,以免拖慢您的存儲庫 您的專案通常會包含較大的文件(例如資料庫、二進制資產、檔案或媒體文件),這會減慢 git 工作流程並使使用限制達到最大。這就是 [大型文件存儲](https://git-lfs.github.com/) 的用武之地 - 它使您能夠將這些大型資產存儲在其他地方,同時使它們可以通過 git 進行跟踪並保持相同的存取控制/權限。 LFS 的工作原理是將這些較大的文件替換為在 git 中跟踪的文本指針。 要使用它,只需執行 `git lfs track <file glob>`,這將更新您的 `.gitattributes` 文件。您可以通過擴展名(例如“*.psd”)、目錄或單獨指定文件。執行 git lfs ls-files 以查看跟踪的 LFS 文件列表。 --- ## Git GC > 使用 [`git gc`](https://git-scm.com/docs/git-gc) 優化您的存儲庫 隨著時間的推移,git repos 會積累各種類型的垃圾,這些垃圾會佔用磁盤空間並減慢操作速度。這就是內置垃圾收集器的用武之地。執行 `git gc` 將刪除孤立的和不可存取的提交(使用 [`git prune`](https://git-scm.com/docs/git-prune)),壓縮文件修訂和存儲的 git 物件,以及一些其他一般的內務管理任務,如打包引用、修剪引用日誌、尊重元資料或陳舊的工作樹和更新索引。 加入 `--aggressive` 標誌將 [積極優化](https://git-scm.com/docs/git-gc#_aggressive) 存儲庫,丟棄任何現有的增量並重新計算它們,這需要更長的時間執行但如果你有一個大型存儲庫可能需要。 --- ## Git Show > 使用 [`git show`](https://git-scm.com/docs/git-show) 輕鬆檢查任何 git 物件 以易於閱讀的形式輸出物件(blob、樹、標籤或提交)。要使用,只需執行 `git show <object>`。您可能還想附加 `--pretty` 標誌,以獲得更清晰的輸出,但還有許多其他選項可用於自定義輸出(使用 `--format`),因此此命令對於準確顯示非常強大你需要什麼。 這非常有用的一個實例是在另一個分支中預覽文件,而無需切換分支。只需執行 `git show branch:file` --- ## Git Describe > 使用 [`git describe`](https://git-scm.com/docs/git-describe) 查找可從提交中存取的最新標記,並為其指定一個人類可讀的名稱 執行 `git describe`,您將看到一個人類可讀的字串,該字串由最後一個標籤名稱與當前提交組合而成,以生成一個字串。您還可以將特定標籤傳遞給它, 請注意,您必須已建立標籤才能使其正常工作,除非您附加了 `--all` 標誌。默認情況下,Git describe 也只會使用帶註釋的標籤,因此您必須指定 `--tags` 標誌以使其也使用輕量級標籤。 --- ## Git Tag > 使用 [`git tag`](https://git-scm.com/docs/git-tag) 在你的 repo 歷史中標記一個特定點 能夠[標記](https://git-scm.com/book/en/v2/Git-Basics-Tagging) 存儲庫歷史記錄中最常用於表示發布版本的特定重要點通常很有用。建立標籤就像 `git tag <tagname>` 一樣簡單,或者您可以使用 `git tag -a v4.2.0 <commit sha>` 標記歷史提交。與提交一樣,您可以使用“-m”在標籤旁邊包含一條訊息。 不要忘記使用 `git push origin <tagname>` 將您的標籤推送到遠程。 要列出所有標籤,只需執行 `git tag`,並可選擇使用 `-l` 進行通配符搜尋。 然後,您將能夠使用 `git checkout <tagname>` 檢出特定標籤 --- ## Git Reflog > 使用 [`git reflog`](https://git-scm.com/docs/git-reflog) 列出對您的存儲庫所做的所有更新 Git 使用稱為參考日誌或“reflogs”的機制跟踪分支尖端的更新。跟踪各種事件,包括:克隆、拉取、推送、提交、檢出和合併。能夠找到事件引用通常很有用,因為許多命令都接受引用作為參數。只需執行 `git reflog` 即可查看 `HEAD` 上的最近事件。 reflog 真正有用的一件事是恢復丟失的提交。 Git 永遠不會真正丟失任何東西,即使是在重寫歷史時(比如變基或提交修改)。 Reflog 允許您返回提交,即使它們沒有被任何分支或標記引用。 默認情況下,reflog 使用 `HEAD`(您當前的分支),但您可以在任何 ref 上執行 reflog。例如 `git reflog show <branch name>`,或者使用 `git reflog stash` 查看隱藏的更改。或者使用 `git reflog show --all` 顯示所有引用 --- ## Git Log > 使用 [`git log`](https://git-scm.com/docs/git-log) 查看提交列表 您可能已經熟悉執行 `git log` 來查看當前分支上最近提交的列表。但是您可以使用 git log 做更多的事情。 使用 `git log --graph --decorate --oneline` 將顯示一個漂亮整潔的提交圖以及 ref 指針。 ![示例 git 日誌輸出](https://i.ibb.co/c1WByg8/Screenshot-from-2022-12-17-20-43-56.png) 您還經常需要能夠根據各種參數過濾日誌,其中最有用的是: - `git log --search="<anything>"` - 搜尋特定程式碼更改的日誌 - `git log --author="<pattern>"` - 只顯示特定作者的日誌 - `git log --grep="<pattern>"` - 使用搜尋詞或正則表達式過濾日誌 - `git log <since>..<until>` - 顯示兩個引用之間的所有提交 - `git log -- <file>` - 顯示僅對特定文件進行的所有提交 或者,只需執行 `git shortlog` 以獲得匯總的提交列表。 --- ## Git Cherry Pick > 使用 [`git cherry-pick`](https://git-scm.com/docs/git-cherry-pick) 通過引用選擇指定的提交並將它們附加到工作 HEAD 有時你需要從其他地方拉一個特定的提交到你當前的分支。這對於應用熱修復、撤消更改、恢復丟失的提交以及在某些團隊協作設置中非常有用。請注意,通常傳統的合併是更好的做法,因為挑選提交會導致日誌中出現重複提交。 用法很簡單,只需執行 `git cherry-pick <commit-hash>`。這會將指定的提交拉入當前分支。 --- ## Git Switch > 使用 [`git switch`](https://git-scm.com/docs/git-switch) 在分支之間移動是我們經常做的事情,`switch` 命令就像是`git checkout` 的簡化版本,它可以用來建立和在分支之間導航,但不像 checkout 在分支之間移動時不會復制修改的文件. 類似於 `checkout -b`,使用 switch 命令你可以附加 `-c` 標誌來建立一個新分支,然後直接跳入其中,例如`git switch -c <新分支>`。執行 `git switch -` 將放棄您所做的任何實驗性更改,並返回到您之前的分支。 --- ## Git Standup > 使用 [`git standup`](https://github.com/kamranahmedse/git-standup) 回憶你在最後一個工作日做了什麼,基於 git 提交 我把它放在最後,因為它不包含在大多數 git 客戶端中,但是您可以使用系統包管理器[輕鬆安裝](https://github.com/kamranahmedse/git-standup#install) ,使用 1 行 curl 腳本,或從源程式碼建置。 如果您的老闆要求您每天站立一次,以更新昨天的工作,但您永遠記不起自己到底做了什麼——這個適合您!它將顯示一個格式良好的列表,列出在給定時間範圍內完成的所有事情。用法很簡單,只需執行 `git standup`,或使用 [這些選項](https://github.com/kamranahmedse/git-standup#options) 指定應顯示哪些資料(作者、時間範圍、分支機構等)。 --- ## 結論 希望對您有幫助!

寫文件基本技巧:如何替專案寫一份優質 README 文件

為您的開源專案提供良好的文檔是一項重要(且經常被忽視)的功能,可以促進採用並展示您的軟體的全部潛力。 不幸的是,文檔的增長速度通常比程式碼慢得多,主要是因為一些看起來相當簡單的實現,會產生大量可能的用例和變化。不可能涵蓋所有可能的場景,這就是為什麼技術作家的首要工作是確定範圍和確定優先級。關注基本知識非常重要,必須首先記錄以支持最常見的用例。 在這篇文章,我將分享一些技巧,為您的專案打造一個好的 README 文件。 原文出處:https://dev.to/erikaheidi/documentation-101-creating-a-good-readme-for-your-software-project-cf8 ## README 檔案 專案的 README 文件通常是用戶與您的專案的第一次接觸,因為這是他們在訪問您的專案時首先看到的內容。這就是為什麼優先考慮將好的 README 作為專案文檔的起點很重要。 自然地,不同的專案在 README 中有不同的東西要展示,但這些技巧應該作為大多數軟體專案的良好起點。 ## 1. 少即是多 你可能想把所有東西都放在你的 README 中,比如如何安裝和使用項目,如何部署,如何調試......更詳細地涵蓋這些主題的更完整文檔的鏈接。 當您開始時,只有一個 README 就可以了。很長的 README 沒有吸引力,因為沒有目錄或菜單可供導航,因此更難找到訊息,這最終不利於良好的用戶體驗。鏈接到相關資源的較短的自述文件使專案看起來更有條理且不那麼複雜。 如果我不想為這個專案創建一個專門的文檔網站怎麼辦?那麼,在這種情況下,您可以考慮在根目錄中創建一個 `docs` 文件夾,您可以在其中保存額外的 markdown 文檔,這些文檔可以直接從您的代碼託管平台(假設是 GitHub)瀏覽。 ## 2. 將 README 拆分為其他文檔 對於存儲庫中的文檔,您可以在應用程式的根目錄中創建一個“/docs”目錄,並使用“/docs/README.md”文件作為文檔的入口點或索引。 此文件夾的內容大概就像: - installation.md - 詳細顯示如何安裝項目的文檔。 - usage.md - 項目使用情況和主要命令的更詳細視圖。 - advanced.md - 包含一些進階使用選項和用例的文檔。 這些只是一些可以作為起點的想法。如果您覺得需要創建一個包含子文件夾的更複雜的結構,您應該認真考慮為您的項目創建一個專門的文檔網站(我們將在本系列的後續文章中介紹)。 ## 3. README 文件要點 以下是您的 README 文件中絕對應該包含的一些內容: - 項目的大致概述,包括編寫它的語言、它的作用、它為什麼有用; - 安裝要求; - 安裝文檔的鏈接; - 使用概述,讓用戶簡要了解如何執行它; - 故障排除或測試提示(可以是指向單獨文檔的鏈接); - 連接到其他資源以了解更多訊息。 理想情況下,這些應該是簡短的說明,可在必要時鏈接到更全面的文檔。 根據項目的規模和目標,您應該考慮將其他內容放在那裡: - 指向 CONTRIBUTING.md 文檔的鏈接,其中包含有關用戶如何為您的專案做出貢獻的詳細訊息 - 指向包含項目行為準則的 CODE_OF_CONDUCT.md 文檔的鏈接。 如果您的項目託管在 GitHub 上,這些將顯著顯示在右側欄的項目頁面中,就在“關於”部分的正下方。 ### 示例結構 以下是 markdown 的一般結構,您可以將其用作構建專案自述文件的基礎: ``` # Project Name A paragraph containing a high-level description of the project, main features and remarks. ## Requirements Here you should give a general idea of what a user will need in order to use your library or application. List requirements and then link to another resource with detailed installation or setup instructions. - Requirement one - Another requirement Check the [installation notes]() for more details on how to install the project. ## Usage Include here a few examples of commands you can run and what they do. Finally link out to a resource to learn more (next paragraph). For more details, check the [getting started guide](). ## Useful Resources Include here any other links that are relevant for the project, such as more docs, tutorials, and demos. ``` ## 4. 使用徽章 您可以使用徽章通過自動從專案中提取的快速訊息來豐富您的 README,例如最新構建的狀態、最新的穩定版本、專案許可證等。 有不同的服務可以為開源專案提供徽章。正如@mohsin 在這篇文章的評論部分所指出的,您可以直接從 GitHub Actions 中提取徽章,方法是轉到您的工作流程頁面,單擊右上角顯示的三個點,然後從中選擇“創建狀態徽章”菜單: ![屏幕截圖顯示在哪裡可以找到菜單以從 github 操作創建狀態徽章](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bpb6g6xofhwm8vctwcem.png) 這將向您顯示一個帶有降價代碼的對話框,您可以將其複製並貼上到您的 README 文件中。 另一個不錯的選擇是使用網站 [Shields.io](https://shields.io/),它提供了幾種不同的徽章,您可以在您的開源項目中免費使用。 例如,這是顯示最新版本 [yamldocs](https://github.com/erikaheidi/yamldocs) 的圖像 URL: ``` https://img.shields.io/github/v/release/erikaheidi/yamldocs?sort=semver&style=for-the-badge ``` 這會生成以下徽章,顯示最新版本: ![yamldocs 的最新穩定版本](https://img.shields.io/github/v/release/erikaheidi/yamldocs?sort=semver&style=for-the-badge) 這是帶有多個徽章的 README 示例: ![顯示來自 yamldocs 項目自述文件的徽章](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5frlxoex4fyke8ra1avf.png) ## 結論 文檔是任何軟體專案的重要組成部分,應該從一開始就認真對待。最好的開始方式是創建一個好的自述文件,向用戶顯示基本信息,而不是用他們可能不需要的內容來淹沒他們,以便開始使用您的專案。

新手不用急著學 TypeScript,不如先把 JavaScript 學熟練

> 為什麼有些 JavaScript 工程師沒在用 TypeScript 呢?原因有哪些? 我在推特問大家:為什麼你還沒用 TypeScript? ![](https://res.cloudinary.com/practicaldev/image/fetch/s--By6b0ozU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3uto8rrbud9yv303gs5b.png) 這篇文章簡單整理大家的答案。 原文出處:https://dev.to/codewithvoid/ive-got-99-problems-but-learning-typescript-aint-one-o70 讓我們開始吧。 ## 先征服 JavaScript 👨‍🏫️ 很多新手和初學者給出了“我還在學習 JS”的原因。 可以理解,他們現在不想承擔超過他們可以吸收的東西。 他們中的大多數人有興趣在未來嘗試一下,而有些人則在尋求指導,看看是否應該這樣做。 ## 純 JavaScript 就很夠用 👌 已經在使用 JS 的開發人員有一個問題 → “為什麼需要?”。 他們不打算遷移過去,因為有一個用 JavaScript 編寫的大型程式庫、易於調試,或者僅僅是因為他們對 JS 感到滿意,因為它可以完成工作。 他們的座右銘是:“如果夠用,就不要碰它”。 ## 對不起,晚點再考慮🕒 一些有經驗的 JS 開發人員已經計劃學習 TypeScript,但認為合適的時機還沒有到來。 與不願意遷移的開發人員不同,這些開發人員看到了 TypeScript 的價值。只是他們還沒有找到合適的專案,這證明了學習曲線的確存在。 此外,他們希望工具(如支持在瀏覽器中本地運行 TS 程式碼)在未來得到改進。 ## 要看情況使用🧐 一些開發人員花時間學習了 TypeScript,但並沒有在每個專案中都使用。 根據他們的說法,主要原因是: - 需要跟團隊一起 - 應用程式已上線 - 程式庫太龐大 他們說“對於個人專案和簡單的應用程序,TypeScript 是一種矯枉過正”。 ## ECMA 即將到來🏁 最後,一些回應是關於 ECMA 6 已經支持足夠的現代性,可在 JS 中編寫乾淨的代碼。 這些開發人員建議,如果你足夠了解 JavaScript 並使用圍繞它構建的工具,你就不需要 TypeScript。 此外,他們希望 TypeScript 中的有用功能最終會包含在原生 JavaScript 中,所以為什麼要費心研究 2 個學習曲線。 ## 總結📝 您對 TypeScript 的心得是什麼?歡迎在留言處分享。

2023 前端框架比較:Svelte vs React,該學哪一個呢?

在 Web 開發世界中,有時感覺就像每天都有新的前端框架問世!大多數來去匆匆,但有一件事是肯定的:Svelte 將繼續存在。 不過,這並不意味著您應該放下一切並在今天學習!追逐最新潮流會讓您分心和不知所措。 這篇文章將一勞永逸地回答:**我應該學習 React 還是 Svelte?**。 您將看到一些程式碼範例,這些範例解釋了為什麼 React 開發人員會為 Svelte 瘋狂,但我們也必須實際一點。 React 已經存在了很長時間。有更多的套件、支援、職缺。 Svelte 還能取代 React 嗎?讓我們找出答案! - 原文出處:https://dev.to/mikehtmlallthethings/svelte-vs-react-which-framework-to-learn-in-2023-50gf --- * 📍 什麼是 React? * 📍 什麼是 Svelte? * 📍 React 和 Svelte 的 5 個區別 * Svelte 的捆綁包尺寸更小 * Svelte 更容易學習 * Svelte 使用純 HTML、CSS 和 JavaScript 進行編譯 * React 有更多的套件 * React 有 React Native * 📍 React 是庫還是框架? * 📍逐行比較 React 和 Svelte 專案 * 📍 Svelte 比 React 快嗎? * 📍 何時從 React 切換到 Svelte * 📍 結論 ### **What is React?** 讓我們從 React 開始。 React 是一個漸進式 JavaScript 前端框架(或函式庫,具體取決於您詢問的對象),可幫助您構建複雜的 Web UI。 它由 Facebook(現為 Meta)於 2013 年創建,能夠很快在前端 Web 開發領域站穩腳跟。 React 的核心是狀態和渲染狀態,這意味著要使用它,您必須添加其他庫來處理客戶端功能和路由。 ### **What is Svelte?** Svelte 也是一個前端 JavaScript 框架,但採用了更加一體化的方法。 Svelte 具有內建的狀態管理、路由和客戶端 (DOM) 功能。 ![](https://scrimba.com/articles/content/images/size/w1600/2022/12/React-vs-Svelte-functionalities.png) React 需要第三方庫和工具,如 Redux、React Router、JSX,而 Svelte 內建了很多這樣的功能。它不太靈活,但更方便和一致。 它採用更幕後(魔術)風格的方法,它直譯非常基本的 JavaScript 程式碼並為您處理 UI 和狀態管理: ``` <script> let count = 0; function handleClick() { count += 1; } </script> <button on:click={handleClick}> Clicked {count} {count === 1 ? 'time' : 'times'} </button> ``` Svelte 由紐約時報的開發人員 Rich Harris 於 2016 年創建,用於以高效的方式處理複雜的圖表和圖形。它從那裡成長為 React 和 Vue 之類的備受喜愛的競爭對手。 ### **React 和 Svelte 之間的 5 個區別** ### **1。 Svelte 的構建包大小要小得多** 我們在下面構建的相同(功能)應用程序。部署包大小在 React 是 41.2 kB,在 Svelte 是 2.1 kB。這幾乎減少了 **20x** 🤯 為了獲得這些數字,我構建了一個在 Svelte 和 React 中具有相同功能的應用程序。我們將在 React 與 Svelte 代碼分解部分深入研究這些應用程序。 ![](https://scrimba.com/articles/content/images/size/w1600/2022/12/React-vs-Svelte-bundle-size-2.png) 我用 React 和 Svelte 構建了一個相同的應用程序。看看 Svelte 包小了多少! ### **2。 Svelte 更容易學習,因為它的語法簡單** Svelte 採用更幕後的魔術方法,允許您編寫非常少量的樣板或語法糖來完成複雜的綁定。模板語法只是帶有一些額外內容的 HTML,這與 JSX(React 等價物)有很大不同並且更容易學習。 React 變數宣告: ![](https://scrimba.com/articles/content/images/size/w1600/2022/12/React-_-React-vs-svelte_-reactive-variable-declaration.png) Svelte 變數宣告: ![](https://scrimba.com/articles/content/images/size/w1600/2022/12/Svelte-_-React-vs-svelte_-reactive-variable-declaration.png) Svelte 看起來像純 JavaScript,但它具有與 React 完全相同的功能。更新 Svelte 變數將自動更新它所在的 UI 元素。 ### **3。 Svelte 符合純 HTML、CSS 和 JavaScript** Svelte 將您編寫的程式碼編譯成基本的 HTML、CSS 和 JavaScript。它不需要像 React 那樣與你的代碼捆綁在一起! React.js 需要存在於一個 bundle 中以完成所有正確的虛擬 DOM 比較和創建,Svelte 不使用虛擬 DOM 來處理 UI。相反,它選擇了基本的 JavaScript 元素創建函數,例如 document.createElement。 ### **4。 React 擁有更多為它構建的庫和包** React 已經存在了 3 年多,也是目前 JavaScript 框架事實上的王者👑。正因為如此,它擁有大量用戶和公司創建的軟件包。 用戶創建的包通常只是為了使路由和狀態管理更容易,或者添加滑塊、燈箱等。這些並不重要,因為 Svelte 具有可靠的選項,並且兼容/適應大多數 JavaScript 套件。 有點困難的是,要跟任何其他框架之前創建的 React 套件整合時不容易。我在 Solana 和以太坊上從事 Web3 專案時經常遇到這個問題。 ### **5。 React 有 React Native** React Native 是使用率最高和受支持最多的跨平台框架之一。它提供了使用 React 創建 iOS 和 Android 應用程式的能力。全部來自同一個代碼庫。由於其成熟度,它擁有大量的庫、支援和學習資源。 儘管有 Svelte 的替代方案,例如稱為 Svelte-native 的 NativeScript 改編版,但它們不具有與 React-native 相同的可靠性和功能。 ### **React 是函示庫還是框架?** 儘管 React 通常被稱為框架,但可以說,由於其範圍,它更像是一個函式庫。它專門負責管理 UI 的狀態並使其與應用程式中的資料狀態保持同步。 因此,它需要第 3 方函式庫來處理應用程式路由 (React Router)、UI 創建 (JSX) 和元件之間的狀態管理 (Redux)。 另一方面,Svelte 內建了上述所有功能,因此更像是一個完整的 UI 管理解決方案。 你可以看到大多數人都同意這是一個函式庫,但仍有一些爭論👇 https://twitter.com/htmleverything/status/1597574223148765185 ### **逐行比較 React 和 Svelte 專案** 比較兩種 Web 技術的最佳方法是深入研究並使用它們進行構建。構建完全相同的應用程序有助於了解每個庫/框架如何處理不同的功能。 讓我們看看: * 條件渲染 * 模板循環 * 更新狀態 * 事件掛鉤 ### **我們在建造什麼?** 編碼是一項口渴的工作,因此我們將構建一個簡單的網絡應用程序,允許用戶跟踪他們全天喝了多少杯水(或🍺)。 額外的好處是顯示每杯喝醉的歷史和時間。 我們將保持 UI 簡單,以更多地關注底層框架。 (見下面的用戶界面) https://codesandbox.io/embed/react-water-example-scrimba-ny5q0m?fontsize=14&hidenavigation=1&theme=dark ### **React** 為了分解代碼,首先讓我們深入了解一些 React 概念和術語👇 React 有幾種類型的語法你需要學習。鉤子、狀態和模板 (JSX) 是主要的。 鉤子 - 允許您進入應用程序的生命週期 State - 允許您根據數據的變化更新 UI 元素。它將“狀態”(或更簡單的變量)更改與 UI 更新聯繫起來 模板 - 允許您直接在 HTML 中使用變量和 JavaScript React 組件的樣式通常由單獨的 .css(或 .scss)文件處理。 ### **React 代碼分解** https://codesandbox.io/embed/react-water-example-scrimba-ny5q0m?fontsize=14&hidenavigation=1&theme=dark&view=editor 變數是使用 useState 掛鉤設置的,它允許更新變量並讓 UI 動態呈現這些更新。 `useEffect` 用於在加載應用程序時設置今天的日期。 JSX 模板使用基本的“{}”符號以及 HTML 中的標準 JavaScript 函數,允許顯示變量和循環數組(使用“.map”)。 ### **Svelte** Svelte 採用不同的方法,採用更“幕後魔術”的風格。邏輯看起來很像純 JavaScript。在後台,代碼做的事情幾乎與 React 代碼做的一樣。 Svelte 仍然有像 `onMount` 和 `onDestroy` 這樣的鉤子,但是簡單地分配一個變量並讓它完全響應並在模板 (HTML) 中可訪問不需要任何特殊的語法糖。 另一個很大的區別是您可以直接在 Svelte 組件中編寫 CSS/SCSS。這只是一個選項,因為您仍然可以像在 React 中一樣導入樣式,但我注意到大多數 Svelte 項目都使用樣式內組件。 ### **Svelte 代碼分解** https://codesandbox.io/embed/svelte-water-example-scrimba-2vsoid?fontsize=14&hidenavigation=1&module=%2FApp.svelte&theme=dark&view=editor 上面的代碼實例化了一個 cupsOfWater 數組,將新的日期變量設置為當前日期。 聲明一個函數來創建一個新日期並將其存儲在一個名為 cup 的變量中,然後將其添加到 cupsOfWater 數組中。 模板部分更接近 HTML 並增加了一些功能。再次使用“{}”表示法,您可以從“<script>”部分引用任何聲明的變量。您還可以使用事件偵聽器(如 `on:click`)、條件(如 `{#if}`)和使用 `{#each}` 循環。 ### **Svelte 比 React 快嗎?** 是的,從快速的 HTML 生成到更快的構建和開發環境,Svelte 的性能都大大優於 React。 * 生成 HTML * 根據狀態更新 UI * 第一次內容豐富的渲染 * 互動時間 * 速度指數 所有這些都看到了可衡量的差異,而 Svelte 具有優勢。您的應用程序越大越複雜,差異就越明顯。 在 Zeitspace 的一篇文章中可以看到性能比較 https://www.zeitspace.com/blog/we-built-an-app-with-svelte.-heres-what-we-learned ### **Svelte 比 React 好嗎?** 當開始一個新專案時,Svelte 有足夠的優勢,它應該始終是一個考慮因素。 話雖如此,React 在使用率方面仍然絕對勝過 Svelte。這可能會導致專案的第 3 方插件支持、僱用和壽命問題。 不過,為了應對這一點,Svelte 語法的易用性使其非常容易上手,尤其是對於 React 開發人員而言。這是公司在招聘 Svelte 項目時可以藉鑑的東西(不要將自己局限於 Svelte 開發人員)。 ### **何時從 React 切換到 Svelte** Svelte 是構建複雜網站或 Web 應用程序的絕佳選擇。許多老牌公司已經開始將 Svelte 用於內部和外部應用程序: * 1Password * Avast * Chess.com * Alaska Airlines * Fusion Charts * Rakuten * GoDaddy * IBM * Square * 紐約時報 * 飛利浦 但這並不意味著您必須將當前的 React 應用程序放入垃圾桶! 那麼什麼時候是接觸 Svelte 的合適時機? 如果您的應用/網站: * 由於頻寬限制,需要較小的包大小 * 需要盡可能快 * 需要快速建造 When is not the right time to reach for Svelte? 什麼時候不適合使用 Svelte? 如果您的應用/網站: * 嚴重依賴第 3 方集成/工具 * 需要轉換為移動應用程序 這些很快就不會成為問題,但在投入之前確實需要進行一些研究和盡職調查。 ### **結論** 建議投入其中並嘗試在 Svelte 中構建一些東西。如果你來自 React,我幾乎可以向你保證你會喜歡它的簡單性和速度。

寫 React 時必備的幾個 VS Code Extensions:新手推薦

來看看一些對 React 開發人員最有用的 VS Code 外掛吧! - 原文網址:https://dev.to/devland/vs-code-extensions-you-should-use-as-a-react-developer-2f6i ## ES7 React/Redux/GraphQL/React-Native snippets ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qoxlb7rz6gzkx906xfr5.jpg) 最流行的外掛之一,由 React 開發人員提供,也由 React-Native 開發人員參與。它帶有許多速記前綴,您可以輕鬆使用它來加快開發過程。 這個外掛提供了很多你可能不知道的功能。一旦你安裝了這個驚人的外掛,創建一個新文件並輸入 rfce 然後按回車鍵,這將生成一個 React 功能組件,導入 React 並導出元件。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8m942g0szndpv3bwprrb.jpg) 它還允許您在幾秒鐘內創建不同的 es7 片段,只需輸入前綴簡寫並按 enter。 此外,如果您使用的是 Redux 或 GraphQL,此外掛也為它們提供了程式碼片段。 ## VSCode React Refactor ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aa1etaf6lasubpmsjxgf.jpg) 簡單,但非常有用。允許您將 JSX 部分提取到新元件、文件等。使用類別、函數和箭頭函數並支持 TypeScript 和 TSX。 ## Prettier ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7tddr5birva6pja6ygoa.jpg) 經過多年使用 Prettier,我認為它是任何專案的都好用的外掛。這是一個自動為你格式化程式碼的工具。它有助於保持程式庫的一致性,因為無論團隊中的開發人員有什麼個人偏好,所有程式碼都將以相同的方式格式化。 ## Eslint ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6l039819s4qx6ngf0e8i.jpg) 用於查找程式碼中的錯誤和缺陷。它可以幫助開發人員編寫沒有錯誤和警告的優質程式碼。 此外,它可以自動修復錯誤和警告。 ## Stylelint ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufskyyg4id7ets3rcjnt.jpg) 和ESLint類似,也是一個linter,但是針對樣式。它可以檢測並突出顯示不正確的樣式,並有助於保持樣式一致和有序。更重要的是,它適用於純 CSS 以及 SCSS 和 LESS 等預處理器。 ## GitLens ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6wmh3we9qrykvxari4mo.jpg) 增強了 Visual Studio Code 中內置的 Git 功能。它可以幫助您通過 Git 責備註釋和 code lens 一目了然地可視化代碼作者身份,無縫導航和探索 Git 存儲庫。 ## Git History ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzsboqxicv3bs8f0n7p1.jpg) 允許您查看 git 日誌和文件歷史記錄,並比較分支或提交。 ## Settings sync ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iphz26rbvb85pnuzcijf.jpg) 您是否曾經重新安裝作業系統或更改您編寫程式碼的設備、繼續安裝 VS Code、然後發現您需要重新安裝所有外掛?它可以自動保存你的外掛和 VS Code 設置,然後在另一台設備上安裝和配置它們。 ## Bracket Pair Colorization Toggler ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xw0embc8ohxzmaw54fq.jpg) 非常簡單但有用的擴展。突出顯示匹配的括號對。 ## Auto Close Tag ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yda8pr1303sn1kdzwoz8.jpg) 一個簡單但最有用的 React 外掛之一。它所做的是一件非常簡單的事情。 Auto close tag,顧名思義,為元素創建一個結束標籤,這意味著開發人員不需要編寫結束標籤。這可能看起來很簡單,但實際上,自動關閉標籤非常有用。 ## Auto Rename Tag ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7kjq4bz8u1ccgxgk2w9t.jpg) 自動重命名成對的 HTML/XML 標籤。 ## Auto Import ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zy56itc3bb5jvecscf2v.jpg) 自動為所有可用導入查找、解析並提供代碼操作和代碼完成。適用於 TypeScript 和 TSX。 ## Import Cost ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4wxw0io8difxgthdan5c.jpg) 在 React 中,安裝和導入套件是非常常見和必要的。導入大量套件可能會導致性能問題,因為其中一些包可能很重。此外掛在編輯器中顯示套件的大小。 ## Jumpy ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cp8cldekpyxyesyz1o8j.jpg) 您通常如何從一行程式碼轉到幾行和空格之外的特定關鍵字?多次使用鍵盤箭頭或單擊滑鼠?使用 Jumpy,您可以更有效率,因為它可以讓您快速跳轉到特定單詞。 ## i18n Ally ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jmqx39hkds4lbeoytb1p.jpg) 如果您的應用程序支持多種語言,就非常好用。 Formatting toggle ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhhj774y6xeapll2tomq.jpg) 在某些情況下,我們希望暫時禁用像 Prettier 這樣的代碼格式化程序。這可以通過 Formatting toggle 外掛來完成,無需修改編輯器設置。 ## Npm intellisense ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/75wl3nmlkporzfsnxl6g.jpg) 為導入語句中的 npm 模塊提供自動完成功能。 ## Web Accessibility ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3lni8zqwdh4ngwyk1rm.jpg) 用於提高 Web 應用程序可訪問性的出色插件。它突出顯示了您應該考慮更改的元素,還提供了有關如何更新它們的提示。 ## Live Share ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/74okun8atu01lphpjo7c.jpg) 您願意與其他人協作編寫您的代碼嗎? 此外掛使您能夠與他人實時編輯和調試代碼。 ## Better comments ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/odj7yo1a5sntmhkl4x57.jpg) 用於在您的代碼中創建更人性化的註釋。它可以將評論分類為警報、查詢、待辦事項和突出顯示,並以不同的顏色顯示它們。 ## Docker ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/patpizcxw2hs6gu823em.jpg) 如果您的應用程序是使用 Docker 部署的,您可以考慮使用來簡化構建、管理和部署來自 VS Code 的容器化應用程序。 ## Remote — SSH ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kk6amn6yubsmio7uen68.jpg) 您是否需要訪問服務器才能遠程編輯文件?遠程 SSH 讓您可以使用任何帶有 SSH 服務器的遠程機器作為您的開發環境。您可以輕鬆地在遠程和本地開發環境之間切換。 ## WSL ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2kd4n337eomix1ba0tn7.jpg) 如果您更喜歡在 Linux 上開發您的應用程序,但您的主要操作系統是 Windows,您可以考慮使用 Windows 子系統 Linux (WSL)。如果這樣做,那麼您可能會發現 WSL 擴展很有用,因為它可以讓您在 Windows 上使用 Vs Code構建 Linux 應用程序。在使用基於 Linux 的工具、運行時和實用程序進行開發時,您可以獲得 Windows 的所有生產力。 ## 實時服務器 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rzaylae1618ndvty1agf.jpg) 如果您需要在文件更改時通過實時瀏覽器重新加載來快速啟動實時服務器,很推薦。 ## Debugger for Chrome and Debugger for Firefox ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5hqzk58hdihl2syoctg5.jpg) 調試器提供了許多有用的功能,例如在斷點處暫停代碼執行、變量檢查等。這些擴展提供了 VS Code 編輯器內部的調試功能。 ## Change-case ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qeoqoevy2a6d646ht1ir.jpg) 顧名思義,此擴展允許您更改當前選擇或當前單詞的大小寫。如果您有很長的文本或想將多個變量轉換為相同的大小寫,這將非常有用。 ## Regex Previewer ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pr4eesyhl5bpj0afhhll.jpg) 大多數開發人員很少編寫 Regex 表達式。但是,如果必須,此擴展可能會非常方便。它在並排文檔中顯示當前正則表達式的匹配項。 ## DotENV ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19cpgt5rvygiysu87qi8.jpg) _.env_ 文件的語法突出顯示。 ## 結論 希望對您有幫助!

德國資深架構師:給新手工程師的幾點建議

一名資深的德國軟體架構師 Jeroen De Dauw,寫了一篇很好的文章,給新手工程師一些寫程式的建議。 - 原文出處:https://dev.to/jeroendedauw/advice-for-junior-developers-30am --- ## 給新手工程師的一般建議 ### 1. 程式碼不是重點 作為開發者,我們喜歡寫程式。大多數工程師希望收到的任務明確,可以不用管技術之外的事情,專心解決有趣的技術挑戰。 請花足夠的心力去確認,您正在解決正確的問題。引用管理學大師 Peter Drucker 的話:高效率地去做一件根本沒必要的事情,結果依然是完全沒意義。儘早、經常去搜集回饋,透過「持續交付」來向真正的用戶互動,成為敏捷(Agile)的工程師。 軟體開發成本高昂,現實世界專案的絕大部份工作都是在維護而已。再加上目標應該是對用戶、對生意有幫助,所以結論就是:寫程式最好的方法,經常是完全不寫。引用比爾蓋茲的話:用程式碼有幾行來衡量工程進度,就像用重量來衡量飛機的製造進度。 另請參閱:YAGNI 原則、KISS 原則、The Last Responsible Moment 文章。 ### 2. 軟體設計很重要 在我開發生涯的前五年,我以為軟體設計是架構師或其他特殊職位的人在做的事。我以為開發者專注在完成任務即可,以為軟體設計、最佳實踐、寫測試這些,都不關我的事。我的程式能跑,我的生產力很高,我以為這樣就對了。 直到我閱讀了 Robert C. Martin 的 Clean Code,這書刺激了我對軟體設計的關注,並包含許多範例與啟發。其中最啟發我的是:走得快的唯一方法,就是走得好。也就是說,如果你把事情搞得一團糟,結果只會讓你速度更慢。 學習寫出設計良好的乾淨程式碼,需要時間和精力。而且剛開始的時候,會寫比較慢,並且會犯錯誤。 ### 3. 使用最佳實踐 寫測試通常會有幫助。雖有例外,但大多數時候,寫自動化測試會大有幫助。寫測試就是一種最佳實踐。 如果你不太會寫測試,請遵循最佳實踐並為所有內容寫測試。**開始時,盲目遵循最佳實踐比遵循自己弱弱的判斷要好**。一段時間之後,您將知道怎麼寫測試比較有效,並能夠區分您搞砸了和不值得編寫測試的情況。因為 bug 變少了、重構起來更輕鬆了,您將開始理解測試帶來的深入的價值。**到有了自己的判斷力後,您將能夠超越最佳實踐**。 此建議適用於您在學習任何最佳實踐的新手時期。自動化測試只是一個例子。 有個陷阱要注意,明智的最佳實踐,與荒謬、適得其反的做法之間,只有一線之隔。因為大多數程式碼都很亂,而且大多數開發者(包括資深人員)不了解軟體設計的基礎知識,因此事情就更複雜了。有一個好的指導者很重要。除此之外,根據我自己的經驗,要小心只存在您的語言、框架社群的最佳實踐。尋找那些已經存在了幾十年的長青建議比較好。 --- ## 給新手工程師的技術建議 ### 4. 寫測試 寫自動化測試。也許在寫程式之前先寫測試,例如運用測試驅動開發(TDD)。這讓您可以輕鬆反覆驗證幾段程式是否正確,而不用一直手動跑測試、除錯。 > 你覺得先寫測試很煩嗎?但之後再忙著抓 bug 有比較好? 更重要的是,測試為您重構時提供了額外保障。你需要持續重構來保持程式乾淨。沒有可靠的測試保障,程式碼就可能越變越亂。 如果您的程式碼設計不佳,例如使用繼承進行重用,或使用靜態函數,則編寫測試會很困難。另一方面,如果您有遵循 SOLID 原則、沒有全局依賴項,那麼寫出好的測試並不困難。 設計好測試也很重要,因為糟糕的測試只會拖慢開發速度。避免將測試綁定到被測程式碼的實作細節或系統結構。 ### 5. 不要用繼承來做到程式碼重用 這是讓人以為是最佳實踐的其中一個反例。我的建議是:剛開始時,根本就不要用繼承來做到程式碼重用。這通常都幫助有限,而且帶來一大堆麻煩。請多用組合、少用繼承(關鍵字:composition over inheritance)。 ### 6. 寫出 OOP 程式碼 學習 SOLID 原則,避免寫出 STUPID 原則的程式碼 ( https://williamdurand.fr/2013/07/30/from-stupid-to-solid-code/ )。理解這些原則和反模式非常有價值。 創造一些真正的物件。只有靜態方法的類別,根本不算是物件導向。盡量避免完全使用靜態寫法。 ### 7. 寫出函數式程式碼 不要把函數式程式設計,跟指令式程式設計搞混了。 重點不是完全切換到函數式語言。而是學習使用函數式風格的優點。例如減少狀態、讓函數專心一件事。另請參閱:https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell ### 8. 程式碼稍微重複沒關係 將一大塊程式碼到處複製貼上當然很不好。有尊嚴的開發者很快就發現這一點,並開始遵循某種形式的:不重複自己原則 Don't Repeat Yourself (DRY)。不幸的是,對 DRY 的追求往往會導致過度工程和額外的複雜性。所以會有一條新原則:寫兩次原則 Write Everything Twice(WET)。也就是僅在第三次出現重複時,才動手改善重複段落。 ### 9. 型別、命名、註解 試著寫一些能夠表達自我的程式碼,避免寫註解。 > 每次寫註解時,都應該要皺一下眉頭,感受到自己的表達能力有點失敗。 —— Robert C. Martin 註解很危險,因為有可能說謊。程式碼可以不更新註解就修改,那一開始的註解就變錯誤了。這種情況下,註解不但沒幫助,還會誤導到別人。 要寫出能夠表達自我的程式碼: - **一個函數只做一件事** 因為只做一件事,就能給一個清楚的命名。 - **減少狀態** - **使用型別** 定義清楚的型別,加上跑測試,能讓系統更穩定。 - **減少混合型別** 避免可以同時是整數、布林值或字串的參數或回傳值。如果讓每個函數專心一件事,這自然會做到。 - **寫測試** 良好的全面測試,也同時會是程式碼的使用說明範例。 Robert C. Martin 的書 Clean Code 在命名和寫註解方面有提供一些很好的經驗法則。 --- 以上,希望對大家有幫助!

關於 TypeScript 中 Utility Types 的小知識:新手推薦

TypeScript 的型別系統很強大,大部分專案都在用。此外,在 TypeScript 中,其實有提供一些 Utility Types 來輔助我們進行型別定義與操作。今天與您分享其中五個。 - 原文出處:https://dev.to/murillonahvs/a-little-about-typescript-utility-types-1epd ### Summary - Pick - Omit - ReadOnly - Partial - Required --- ## 1. Pick(Type, Keys) Pick utility type 是從現有型別中選取某些屬性來生成新的型別。 基本上,Pick 從指定型別中刪除除指定鍵之外的所有鍵。 ``` type Person = { name: string lastName: string age: number hobbies: string } type SomePerson = Pick<Person, "name" | "age"> // type SomePerson = { // name: string; // age: number; // } ``` --- ## 2. Omit(Type, Keys) Omit utili type 與 Pick 型別相反,Omit 是寫出要省略的屬性,而不是要保留的屬性。 ``` type Person = { name: string lastName: string age: number hobbies: string } type SomePerson = Omit<Person, "lastName" | "hobbies"> // type SomePerson = { // name: string; // age: number; // } ``` --- ## 3. Readonly(Type) Readonly utility type 用於所有屬性都設置成唯讀的型別。無法為屬性分配新值,不然就跳 TypeScript 警告。 ``` type Person = { name: string } type ReadOnlyPerson = Readonly<Person> const person: ReadOnlyPerson = { name: "Fizz", } person.name = "Buzz" // Cannot assign to 'name' because it is a read-only property. ``` --- ## 4. Partial(Type) Partial utility type 用於所有屬性都設置為選填的型別。 ``` type Person = { name: string lastName: string age: number address: string } type PartialPerson = Partial<Person> // type PartialPerson = { // name?: string | undefined; // lastName?: string | undefined; // age?: number | undefined; // address?: string | undefined; // } ``` --- ## 5. Required(Type) Required utility type 與 Partial 相反。要求要定義好所有屬性。可用來避免選填屬性出現在此型別中。 ``` type Person = { name?: string lastName?: string age?: number address?: string } type RequiredPerson = Required<Person> // type RequiredPerson = { // name: string; // lastName: string; // age: number; // address: string; // } ``` --- 以上,簡單舉例五個分享,有很多好用的 utility type,歡迎查看官網了解更多: https://www.typescriptlang.org/docs/handbook/utility-types.html

在 React 中使用 Design Patterns:以 Strategy Pattern 舉例

在 React 前端開發時,常常會需要在不同的元件、hook、utils 中寫一些邏輯。 有些時候,使用策略模式會很有幫助,這篇文章給您參考。 - 原文出處:https://dev.to/itshugo/applying-design-patterns-in-react-strategy-pattern-enn ## 出問題了:霰彈槍手術(Shotgun Surgery) Shotgun Surgery 是一種程式寫很爛的信號。想對程式規格做一點小修改,需要改一大堆地方。 ![](https://refactoring.guru/images/refactoring/content/smells/shotgun-surgery-01-2x.png) 在專案中通常如何發生?假設我們需要為產品寫一個報價卡片,我們根據客戶所在國家,調整價格、貨幣、折扣方式和文字說明: ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5iz9oso7ozaqm0qibd76.png) 大多數工程師可能會這樣寫: - 元件:`PricingCard`、`PricingHeader`、`PricingBody`。 - Utility functions:`getDiscountMessage`(在 **utils/discount.ts** 中),`formatPriceByCurrency`(在 **utils/price.ts** 中)。 - `PricingBody` 元件會計算最終價格。 完整程式碼範例:https://codesandbox.io/s/react-strategy-pattern-problem-h59r02?from-embed 現在假設我們需要更改一個國家/地區的定價計劃,或為另一個國家/地區添加新的定價計劃。您將如何處理這段修改?您必須至少修改 3 個地方,並向已經滿亂的 `if-else` 區塊添加更多條件: - 修改 `PricingBody` 組件。 - 修改 `getDiscountMessage` 函數。 - 修改 `formatPriceByCurrency` 函數。 如果您聽說過 S.O.L.I.D 原則,我們已經違反了前 2 條原則:單一職責原則和開閉原則。 ## 解決方法:策略模式 策略模式非常簡單。我們可以簡單的理解為,每個國家的定價方案都是一個策略。在那個策略類別中,會實現該策略的所有相關邏輯。 假設您熟悉 OOP,我們可以有一個實現共享/公共邏輯的抽像類別(`PriceStrategy`),然後具有不同邏輯的策略將繼承該抽像類別。 `PriceStrategy` 抽像類別如下所示: ``` import { Country, Currency } from '../../types'; abstract class PriceStrategy { protected country: Country = Country.AMERICA; protected currency: Currency = Currency.USD; protected discountRatio = 0; getCountry(): Country { return this.country; } formatPrice(price: number): string { return [this.currency, price.toLocaleString()].join(''); } getDiscountAmount(price: number): number { return price * this.discountRatio; } getFinalPrice(price: number): number { return price - this.getDiscountAmount(price); } shouldDiscount(): boolean { return this.discountRatio > 0; } getDiscountMessage(price: number): string { const formattedDiscountAmount = this.formatPrice( this.getDiscountAmount(price) ); return `It's lucky that you come from ${this.country}, because we're running a program that discounts the price by ${formattedDiscountAmount}.`; } } export default PriceStrategy; ``` 我們只需將實例化的策略作為 prop 傳遞給 PricingCard 元件: ``` <PricingCard price={7669} strategy={new JapanPriceStrategy()} /> ``` `PricingCard` 的 props 定義為: ``` interface PricingCardProps { price: number; strategy: PriceStrategy; } ``` 同樣,如果您了解 OOP,那麼我們不僅在使用繼承,而且還在此處使用多態性(Polymorphism)。 完整程式碼範例:https://codesandbox.io/s/react-strategy-pattern-solution-mm0cvm?from-embed 使用這個解決方案,我們只需要添加一個新的策略類別,而不需要修改任何現有程式碼。這樣,我們也滿足了 S.O.L.I.D 原則。 ## 結論 因為我們在 React 程式碼中檢測到程式碼發臭:Shotgun Surgery,所以我們使用了策略模式來解決它。 ### Before ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wn31uolfo6xfy3mh8fo.png) ### After ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xheeb2splcwj2kkqwsfo.png) 現在邏輯都存在一個地方,不再分佈在許多地方。 --- 以上是 Strategy Pattern 的簡單說明,希望對您有幫助。

36 個免費、漂亮的 React UI 模板與主題套件

網路上免費的 React 版型資源不太好找,最好有一份懶人包。 這份列表整理了各式各樣的模板與主題套件,希望對您有幫助。 - 原文出處:https://dev.to/davidepacilio/35-free-react-templates-and-themes-32ci --- ##1. Open ![](https://dev-to-uploads.s3.amazonaws.com/i/gy9nddokri1vobwrtbna.jpg) [**Live demo**](https://open.cruip.com/) / [**Download**](https://github.com/cruip/open-react-template) Open 是一個免費的 React 模板,專為開源專案、線上服務、數位產品,創建快速、專業的登陸頁面而生。為了吸引潛在客戶和電子郵件訂閱者,Open 提供了一個多功能的資源庫,其中包含時尚、簡約和可重複使用的元件和元素。 --- ##2. Atomize ![](https://dev-to-uploads.s3.amazonaws.com/i/ks2st96gb0tbu1ybuy6k.jpg) [**Live demo**](https://atomizecode.com/) / [**Download**](https://github.com/proksh/atomize) Atomize 是一個 React UI 框架,旨在幫助開發人員與設計師合作,輕鬆構建一致和諧的用戶界面。由於樣式指南和靈活網格等資源的完美結合,Atomize 適合建立任何類型的響應式網站。 --- ##3. Treact ![](https://dev-to-uploads.s3.amazonaws.com/i/3aw9a273jibs97o2l09m.jpg) [**Live demo**](https://treact.owaiskhan.me/) / [**Download**](https://gumroad.com/l/QaruQ) Treact 是使用 TailwindCSS 作為前端框架開發的現代 React 模板和 UI 組件展示庫。這個精美的檔案庫提供了 7 個內建的主頁、8 個輔助頁面以及 52 個預先設計的元素和段落。每個內容都可以針對家用電腦、平板電腦和移動設備進行擴充。 --- ##4. MatX ![](https://dev-to-uploads.s3.amazonaws.com/i/q99tvy2uvyvol2xet2et.jpg) [**Live demo**](http://matx-react.ui-lib.com/dashboard/analytics) / [**Download**](https://ui-lib.com/downloads/matx-react-dashboard/) MatX 是一個建立在 Material Design 之上的精美 React Native 模板。此模板使用 React、Redux 和 Material UI,它包含為 Web 應用程式提供新造型可能需要的所有基本功能。 MatX 的免費版本可用於輕鬆設置管理面板、用戶管理系統和專案管理系統。 --- ##5. Holly ![](https://dev-to-uploads.s3.amazonaws.com/i/dcrv1qxgo3rgq9a3j3at.jpg) [**Live demo**](https://lukemcdonald.github.io/holly-react/) / [**Download**](https://github.com/lukemcdonald/holly-react) Holly 是一個響應式 React JS 模板,適用於線上服務和數位產品的生產者,能在主要產品仍在開發中時,就開始搜集電子郵件地址。這個模板最初是由 [Cruip](https://cruip.com/) 用 HTML 設計的,然後在這個版本中用 React 撰寫。 --- ##6. OAH-Admin ![](https://dev-to-uploads.s3.amazonaws.com/i/rteeixluj4n09a3s69ma.jpg) [**Live demo**](https://oah-admin.ahmedelywa.com/extra-components/progress/) / [**Download**](https://github.com/AhmedElywa/oah-admin) OAH-Admin 是一個基於 Gatsby 的免費 React 管理儀表板模板,帶有 oah-ui 元件和元素包。這個 React 模板有良好的 UI 元件色調,超級整潔和靈活的格式使任何人都可以輕鬆建立 SaaS 應用程式、管理面板、儀表板。 --- ##7. Gatsby Starter Ghost ![](https://dev-to-uploads.s3.amazonaws.com/i/ocey043yzsdt31f7yi9s.jpg) [**Live demo**](https://gatsby.ghost.org/) / [**Download**](https://github.com/TryGhost/gatsby-starter-ghost) 使用 Ghost 這個基於 Gatsby 的入門模板,輕鬆建立高效能網站。Gatsby Starter Ghost 是一個乾淨而現代的模板,適用於部落格、雜誌或任何新聞網站。該產品專門設計來幫助任何人在網路上建立個人空間並分享想法、創意和更新。 --- ##8. Star Admin ![](https://dev-to-uploads.s3.amazonaws.com/i/hlbf4y4pl4a5od2c8chb.jpg) [**Live demo**](https://www.bootstrapdash.com/demo/star-admin-free/react/template/demo_1/preview/dashboard) / [**Download**](https://github.com/BootstrapDash/StarAdmin-Free-React-Admin-Template) 一個免費的 React Native 模板,提供了無窮無盡的各種基本元素,可以將任何想法變為現實。該模板具有精心製作的儀表板,包含大量整齊排列和組織的元件,它可以完美地與所有最新和現代的瀏覽器配合使用,並且能夠使資料可視化過程更易於管理。 --- ##9. Carolina Admin Dashboard ![](https://dev-to-uploads.s3.amazonaws.com/i/05r7fsc1jzylez5diu6f.jpg) [**Live demo**](https://demo.uifort.com/carolina-react-admin-dashboard-material-ui-free-demo/LandingPage) / [**Download**](https://uifort.com/template/carolina-react-admin-dashboard-material-ui-free/) 如果您正在尋找一個令人驚嘆且實用的 React 儀表板模板,Carolina Admin Dashboard 擁有啟動和運行您 Web 專案所需的一切。這個漂亮的模板建立在 Material-UI 框架之上,採用乾淨清新的設計,遵循所有 Google 的 Material Design 指南。此外,核心結構是完全響應式和開源的。 --- ##10. Tabler ![](https://dev-to-uploads.s3.amazonaws.com/i/nu5vq6j5buk36iz8prsn.jpg) [**Live demo**](http://tabler-react.com/) / [**Download**](https://github.com/tabler/tabler-react) Tabler 是一個免費的 React 管理儀表板模板,非常適合任何類型的後端 Web 應用。此管理模板包含大量精心設計的範例,無需從頭開始,可為您節省大量時間,它還附帶可重複使用的元件,例如按鈕、地圖、圖表、表單等。 --- ##11. React Nice Resume ![](https://dev-to-uploads.s3.amazonaws.com/i/ci5hhvp6ki5o3mpk8zbz.jpg) [**Live demo**](https://nordicgiant2.github.io/react-nice-resume-page/#home) / [**Download**](https://github.com/nordicgiant2/react-nice-resume) React Nice Resume 是一個漂亮的主題,如果您是開發人員、設計師或一般的數位創作者,可以用來宣傳您自己和您的作品。該資源展示了一個獨特的主頁,帶有粒子背景、工作經驗時間線、技能圖表、顯示最新專案的縮略圖、一個帶有功能輸入表單的段落。 --- ##12. Boss Lite ![](https://dev-to-uploads.s3.amazonaws.com/i/zq92otm0bc9t3mwinkxb.jpg) [**Live demo**](http://boss.ux-maestro.com/app/tables/data-table) / [**Download**](https://github.com/ilhammeidi/boss-lite) Boss Lite 是一個基於 React 和 Redux 的管理儀表板模板。此模板為您帶來清新現代的設計和多種配色方案。它支援大多類型的 Web 專案,並且 Flexbox 佈局而變得很流暢。 --- ##13. Chakra UI ![](https://dev-to-uploads.s3.amazonaws.com/i/poootemj2t5caoi4lryt.jpg) [**Live demo**](https://chakra-ui.com/) / [**Download**](https://github.com/chakra-ui/chakra-ui/) Chakra UI 提供了一組好用、可重用的 React 功能元件,使建立好用網站和用戶界面變得非常簡單。 Chakra UI 中的幾乎所有元素都兼容深色模式,它們遵循 WAI-ARIA 指南規範,並構建在 React UI Primitive 之上以實現無限的可組合性。 --- ##14. Black Dashboard React ![](https://dev-to-uploads.s3.amazonaws.com/i/2r1tx4uxug6k1xlnr3pr.jpg) [**Live demo**](https://demos.creative-tim.com/black-dashboard-react/#/admin/dashboard) / [**Download**](https://www.creative-tim.com/product/black-dashboard-react) Black Dashboard React 是用於管理界面的 React 模板。該模板基於 Bootstrap 建立的設計指南,是基於企業的應用程式,是強大後端軟體可用的優秀前端選項。它具有更高等級的切分、設計套件、可重複使用的圖表,能夠不斷改善用戶和開發體驗。 --- ##15. Argon Design System ![](https://dev-to-uploads.s3.amazonaws.com/i/tvrfqzddf6kwmhiwje6x.jpg) [**Live demo**](https://demos.creative-tim.com/argon-design-system-react/) / [**Download**](https://github.com/creativetimofficial/argon-design-system-react) 使用 Bootstrap 4 和 Reactstrap 的 React 設計系統。Argon Design System 帶有 100 多個單獨的元件、內建的範例,並且每個元素都有多種樣式、懸停、焦點狀態,任何人都可以輕鬆使用。該產品是從原型設計到正式上線的完美解決方案。 --- ##16. Devias Kit - Admin Dashboard ![](https://dev-to-uploads.s3.amazonaws.com/i/j7lqqfvgmujtgg1m80oi.jpg) [**Live demo**](https://react-material-dashboard.devias.io/dashboard) / [**Download**](https://github.com/devias-io/react-material-dashboard) Devias Kit 是一個響應式 Material Design 管理儀表板,專為 React 使用 Google 自己的 Material Design 框架建立。可以自定義設置、指令、圖標和樣式。該模板包含清晰直觀的目錄和文件、快速入門文件,如果您想對設計進行任何更改,甚至還有 Sketch 文件。 --- ##17. Dev Blog ![](https://dev-to-uploads.s3.amazonaws.com/i/1tym4ekzrftd6ldcflid.jpg) [**Live demo**](https://ryanfitzgerald.github.io/devblog/) / [**Download**](https://github.com/RyanFitzgerald/devblog) Dev Blog 是一個 React 網站模板,專為快速建立副專案和產品而生。該網站模板帶有一個首頁,其中顯示了部落格名稱、社交媒體圖示以及帶有文字和圖像的文章縮圖。該模板還包括單個文章頁面,有漂亮且精心策劃的排版。 --- ##18. Material PRO ![](https://dev-to-uploads.s3.amazonaws.com/i/scakf4swq5j99hln1xqx.jpg) [**Live demo**](https://wrappixel.com/demos/free-admin-templates/materialpro-reactadmin-lite/main/#/starter/starter) / [**Download**](https://www.wrappixel.com/templates/materialpro-react-admin-lite/) Material Pro 是一個免費的 React Native 模板,為任何需要管理儀表板的人精心製作。這個漂亮而清爽的產品採用模組化和現代設計理念開發,100% 免費使用和下載,並包含許多頁面,可幫助您更快、更輕鬆地建立專案。 --- ##19. Ant Design Landing ![](https://dev-to-uploads.s3.amazonaws.com/i/wnld469wyg4u9pfk31i1.jpg) [**Live demo**](https://landing.ant.design/) / [**Download**](https://github.com/ant-design/ant-design-landing) Landing 是 Ant Design System 建立的模板。內涵不同樣式的首頁和內頁模組。 --- ##20. Isomorphic ![](https://dev-to-uploads.s3.amazonaws.com/i/zy0at5stk267a06n5f95.jpg) [**Live demo**](https://isomorphic.redq.io/dashboard) / [**Download**](https://github.com/pujoey/ismorphic) Isomorphic 是一個易於管理且有吸引力的管理模板,具有大量靈活的元件。 --- ##21. Shards Dashboard Lite ![](https://dev-to-uploads.s3.amazonaws.com/i/71cn55agi3k9er11xk4o.jpg) [**Live demo**](https://designrevision.com/demo/shards-dashboard-lite-react/blog-overview) / [**Download**](https://designrevision.com/downloads/shards-dashboard-lite-react/) Shards 是一個免費的 React 儀表板模板,具有現代設計系統和許多自定義頁面和部分。 --- ##22. uiw ![](https://dev-to-uploads.s3.amazonaws.com/i/e6aakqf9m9g67mstwvi9.jpg) [**Live demo**](https://uiwjs.github.io/) / [**Download**](https://github.com/uiwjs/uiw) uiw 是用於 React 16+ 的高質量 React 元件庫和 UI 工具包。 --- ##23. React Material Admin ![](https://dev-to-uploads.s3.amazonaws.com/i/te6tezfjcp008lb4q7du.jpg) [**Live demo**](https://flatlogic.github.io/react-material-admin/#/login) / [**Download**](https://flatlogic.com/templates/react-material-admin) React Material Admin 是一個建立在 Material-UI 框架之上的 React 儀表板。 --- ##24. Material KIT React ![](https://dev-to-uploads.s3.amazonaws.com/i/cq2xlu4tci8km6p2tia7.jpg) [**Live demo**](https://demos.creative-tim.com/material-kit-react/) / [**Download**](https://www.creative-tim.com/product/material-kit-react) Material UI KIT 是一款免費的 React UI 主題,其設計靈感來自 Google 的 Material Design,設計清新整潔。 --- ##25. Airframe ![](https://dev-to-uploads.s3.amazonaws.com/i/qwt4nv73xjn14a9g09yl.jpg) [**Live demo**](http://dashboards.webkom.co/react/airframe/dashboards/projects/) / [**Download**](https://github.com/0wczar/airframe-react) Airframe 是一個基於 Bootstrap 4 和 React 16 的免費開源 React 應用程式模板。 --- ##26. Gatsby Simplefolio ![](https://dev-to-uploads.s3.amazonaws.com/i/pe3clc53zqsntgh3vw3n.jpg) [**Live demo**](https://gatsby-simplefolio.netlify.app/) / [**Download**](https://github.com/cobidev/gatsby-simplefolio) Gatsby Simplefolio 是一個乾淨、美觀且響應迅速的 React 組合模板。 --- ##27. Ant Design Pro ![](https://dev-to-uploads.s3.amazonaws.com/i/diktnddjjf630tdyyqa8.jpg) [**Live demo**](https://pro.ant.design/) / [**Download**](https://github.com/ant-design/ant-design-pro/) React --- ##28. React SaaS Template ![](https://dev-to-uploads.s3.amazonaws.com/i/yiq5ast9jw3knt8l92l0.jpg) [**Live demo**](https://reactsaastemplate.com/) / [**Download**](https://github.com/dunky11/react-saas-template) --- ##29. Shards React ![](https://dev-to-uploads.s3.amazonaws.com/i/34zfg3e4qbbzklmgr4uh.jpg) [**Live demo**](https://designrevision.com/downloads/shards-react/) / [**Download**](https://github.com/designrevision/shards-react) --- ##30. Base Web ![](https://dev-to-uploads.s3.amazonaws.com/i/8q3bxpsll7k0qrhzdlmj.jpg) [**Live demo**](https://baseweb.design/) / [**Download**](https://github.com/uber/baseweb) --- ##31. Light Blue React Dashboard ![](https://dev-to-uploads.s3.amazonaws.com/i/tfwzjgvh2sa8e5v9a0oa.jpg) [**Live demo**](https://demo.flatlogic.com/light-blue-react/#/app/main/dashboard) / [**Download**](https://github.com/flatlogic/light-blue-react-template) --- ##32. React JS Landing ![](https://dev-to-uploads.s3.amazonaws.com/i/ibuom994cxj3pzb2yzoz.jpg) [**Live demo**](https://react-landing-page-template.herokuapp.com/#page-top) / [**Download**](https://github.com/IssaafKattan/React-Landing-Page-Template) --- ##33. Admin Pro ![](https://dev-to-uploads.s3.amazonaws.com/i/0f1pjehgesa25ts39wx7.jpg) [**Live demo**](https://wrappixel.com/demos/free-admin-templates/adminpro-react-lite/main/#/dashboard) / [**Download**](https://www.wrappixel.com/templates/adminpro-react-admin-lite/#comparison) --- ##34. Blueprint ![](https://dev-to-uploads.s3.amazonaws.com/i/d1owpo8lfg3zfq1p2vpx.jpg) [**Live demo**](https://blueprintjs.com/) / [**Download**](https://github.com/palantir/blueprint) --- ##35. Datta ![](https://dev-to-uploads.s3.amazonaws.com/i/3con3tndvc7au5zg1jb0.jpg) [**Live demo**](http://lite.codedthemes.com/datta-able/react/default/dashboard/default) / [**Download**](https://codedthemes.com/item/datta-able-react-free-admin-template/) --- ##36. Flatlogic One ![](https://dev-to-uploads.s3.amazonaws.com/i/63flhvqcbh7jtfvih9do.jpg) [**Live demo**](https://flatlogic.github.io/one-react-template/#/login) / [**Download**](https://flatlogic.com/templates/one-free-react-template) --- ##結論 我希望這組免費的 React 模板和主題能夠幫助您!

都要 2023 年了還在用 console.log 嗎?來看看 10 個 console 進階用法!

寫 JavaScript 時,仍在使用 console.log 來除錯抓蟲? 是時候**升級你的技能**並學習 JavaScript console 物件的全部功能了。 從 console.table 到 console.time,這些進階方法和技巧將改善您 **debug 訊息的品質和可讀性**,讓您更輕鬆地故障排除和修復問題。 在 2023 年成為 JavaScript 除錯高手吧! - 原文出處:https://dev.to/naubit/why-using-just-consolelog-in-2023-is-a-big-no-no-2429 ## 😞 問題 僅使用 console.log 的最大問題之一是,它會使程式碼混亂且難以閱讀。此外,它本身的資訊量不是很大。它只是輸出你傳遞給它的任何內容的值,沒有任何上下文或其他資訊。 所以,這裡有十個你應該知道的 JavaScript console 物件方法和技巧,值得了解一下! ## 1️⃣ console.table 此方法以可讀且易於理解的格式,輸出資料表格。console.table 不是只顯示陣列或物件,而是以表格格式顯示,使它更易於瀏覽和理解。 ``` // Output an array of objects as a table const users = [ { id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Doe' } ]; console.table(users); ``` 這將以表格格式輸出 users 陣列,每個物件的屬性作為列,物件作為行。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hek6gxo4x73b6mvmlawr.png) ## 2️⃣console.group console.group 和 console.groupEnd。這些方法可以在控制台中,創建嵌套的可摺疊資料組。**這對於組織和構建 debug 訊息非常有用**,讓您可以輕鬆查看程式碼不同級別發生的情況。 ``` console.group('User Details'); console.log('Name: John Doe'); console.log('Age: 32'); console.groupEnd(); ``` 這將在 console 中創建一個嵌套的、可摺疊的資料組,標題為“使用者詳細資訊”。組內的日誌消息將縮進並分組在一起。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ybn1uwvyltjzxcaaytx.png) ## 3️⃣console.time console.time 和 console.timeEnd 可以測量執行程式碼所需的時間。這對於識別程式中的性能瓶頸、效能優化非常有用。 ``` console.time('Fetching data'); fetch('https://reqres.in/api/users') .then(response => response.json()) .then(data => { console.timeEnd('Fetching data'); // Process the data }); ``` 這將測量「從特定 URL 獲取資料並解析 JSON 回應」所需的時間。耗用時間會在控制台中輸出。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3hdvnz2of3an1a21j3c.png) ## 4️⃣console.assert 此方法允許您在程式碼中寫 assertions,這些是應該始終為 true 的語句。如果 assertions 失敗,console.assert 將在控制台中輸出錯誤消息。**這對於除錯抓蟲、確保程式碼正常運作非常有用。 ``` function add(a, b) { return a + b; } // Test the add function const result = add(2, 3); console.assert(result === 5, 'Expected 2 + 3 = 5'); ``` 如果 add 函數在給定輸入 2 和 3 時未返回預期結果 5,就在控制台中輸出錯誤訊息。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y25c157xwhasxnaiakd5.png) ## 5️⃣設置日誌樣式 使用 `console` 物件輸出樣式和顏色。 `console` 物件**允許您輸出不同顏色和樣式的文字**,使您的除錯輸出更具可讀性和更容易理解。 您可以在 console.log 語句中使用 %c 佔位符來指定輸出文字的 CSS 樣式。 ``` console.log('%cHello world!', 'color: red; font-weight: bold;'); ``` 這將輸出文字“Hello world!”,並使用指定的 CSS 樣式,以紅色和粗體顯示。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1p82u116icnlodu046nr.png) ## 6️⃣console.trace 使用 `console.trace` 方法輸出堆疊追踪(stack trace)。這對於理解程式碼中的執行流程、識別**特定日誌消息的來源非常有用。** ``` function foo() { console.trace(); } function bar() { foo(); } bar(); ``` 這將在控制台中輸出堆疊跟踪,顯示導致 `console.trace` 呼叫的函數呼叫序列。看起來像這樣: ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zx16nee1mp0avh04msri.png) ## 7️⃣console.dir 使用 `console.dir` 方法以分層格式輸出物件的屬性。這對於**探索物件的結構**、查看其屬性和方法非常有用。 ``` const obj = { id: 1, name: 'John Doe', address: { street: '123 Main St', city: 'New York', zip: 10001 } }; console.dir(obj); ``` 這將以分層格式輸出 `obj` 物件的屬性,允許您查看物件的結構及其所有屬性和值。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihgkg5e4wxznpaqzb8jr.png) ## 8️⃣console.count 使用 `console.count` 方法計算特定日誌消息的輸出次數。這對於**追蹤特定程式碼路徑的執行次數**以及識別程式碼中的熱點很有用。 ``` function foo(x) { console.count(x); } foo('hello'); foo('world'); foo('hello'); ``` 這將在控制台中輸出字串“hello”,然後是數字 1。然後它將在控制台中輸出字串“world”,然後是數字 1。最後,它會再次輸出字符串“hello”,然後出書數字 2(因為它被呼叫了兩次)。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cx7n8aargexpq1pvqj6n.png) ## 9️⃣console.clear 使用 `console.clear` 方法清除控制台輸出。這能保持您的除錯輸出**有條理和整潔**,讓您更容易專注於您感興趣的訊息。 ``` console.log('Hello world!'); console.clear(); console.log('This log message will appear after the console is cleared.'); ``` 這將輸出字串 “Hello world!”,接著一個空行(因為控制台已清除)。然後它會輸出字串 “This log message will appear after the console is cleared.” ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihzapi1gcin6gtqa600v.png) ## 1️⃣0️⃣console.profile 使用 `console.profile` 和 `console.profileEnd` 方法來衡量程式碼的性能。這對於**識別性能瓶頸和優化代碼**、提高速度和效率非常有用。 ``` console.profile('MyProfile'); // Run some code that you want to measure the performance of for (let i = 0; i < 100000; i++) { // Do something } console.profileEnd('MyProfile'); ``` 這將開始分析 `console.profile` 和 `console.profileEnd` 呼叫之間的程式碼,並在執行 `console.profileEnd` 時在控制台中輸出結果。輸出將包括有關執行所花費時間的詳細訊息、以及其他與性能相關的各種訊息。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wjw25tagjwdupmqxy1d5.png) ## 💭 最後的一些想法 在 2023 年,不要僅僅滿足於 `console.log` - JavaScript 控制台物件中有許多**更強大、更有價值的工具和技術。** 從 `console.table` 到 `console.time`,這些方法和技巧將幫助您提高除錯輸出的品質和可讀性,並使其**更容易排除和修復代碼中的問題**。 所以,為什麼不在 2023 年提高您的除錯技能並嘗試這些技術呢? 以上簡單分享,希望對您有幫助!

經驗分享:Code Review 程式碼審查的藝術

程式碼審查很難。以下是一些心得分享。 - 原文出處:https://dev.to/saminarp/today-i-learned-the-subtle-art-of-code-reviews-3pef --- 我最近在審查 https://github.com/humphd/my-photohub 的一個 PR。 這是我有生以來第一次進行程式碼審查,也讓我知道這項任務有多麼困難。第一次當審閱者,我發現自己盯著程式碼,思考可以做些什麼來讓它更好。感覺相當迷茫。我想出了一些平庸的建議。沒想到什麼厲害的。沒有什麼讓我覺得很滿意的建議。然後是 Dave 教授 https://github.com/humphd 對我正在審查的同一個 PR 進行程式碼審查。我只是坐在那裡,對他看到而我沒看到的細節感到驚訝。他提出了一些大改善,比如更好的程式設計邏輯,以及一些小建議,比如更新專案描述。這些小建議我也可以提出:更好的專案描述、更適合專案的圖示而不是預設的 React 圖示、並為某些事情創建紀錄追蹤。為什麼我會忽略掉 Dave 教授如此優雅、毫不費力就指出的明顯事情? ## 一些程式碼審查的最佳實踐 這是一篇很棒的文章 https://google.github.io/eng-practices/review/reviewer/looking-for.html 我在研究程式碼審查最佳實踐時找到的。 它漂亮地闡述了設計、功能、複雜性、測試、命名、註釋、樣式、一致性、文檔和上下文都是代碼審查的重要組成。 ## 時間、注意力、溝通 好的審查需要時間和注意力。它需要我們批判性地思考程式設計邏輯。對於初學者來說,盯著別人寫的程式碼來建議一些有意義的東西,可能會讓人感到不知所措。害怕犯錯。害怕冒犯寫程式的人。我知道,因為這些我都有感受到。在開源專案中,在提供建設性回饋的同時,在溝通中保持禮貌和尊重很重要。我們有時可能不認同審查,這種時候,我們應該禮貌地溝通。 在給予和接受回饋時,保持開放的心態也很重要。正是通過這種思想交流和回饋,我們才能夠隨著時間一直進步。 如果你有一些寫程式經驗,只要花足夠的時間專心看程式碼,幾乎總是可以提出改進建議。 ## 從小處著手 如果您是初學者,請從小處著手並向他人學習。閱讀 Dave 教授的評論,我學到了很多重要的東西。然後我意識到,只有看到更有經驗的人如何審查程式碼,我才能變得更好。我記下了我在 GitHub 上閱讀他的大量評論所學到的東西。我把這些東西變成了清單: - 如果不清楚,請詢問有關某程式碼的具體問題。 - 找找看未使用的依賴項和優化 package.json 的方法。 - 從整個程式碼庫的上下文中來看事情。 - 留下一些鼓勵的話,指出開發人員做對了什麼! - 專注於功能和相容性。 - 找出清晰的命名和適當的命名約定。 - 查看 README 檔或 CONTRIBUTING.md 檔時,請看看樣式、格式、拼寫和語法的一致性。 - 確保設計和UI看起來不錯。 - 確保單元測試是為這段程式碼適當設計的。 - 確保程式碼符合提供的某個樣式指南。 ## `linters` 會帶給我們信任 程式碼自動檢查器和靜態工具分析器可以幫助審閱者節省大量時間在尋找愚蠢的拼寫錯誤或樣式錯誤。linters 和 sanners 的作用大概就是拼寫和語法檢查。省下了檢查格式和其他風格的麻煩,審閱者可以專注於程式碼的實際邏輯。作為程式碼審閱者,必須使用可用的自動代碼檢查器來節省時間和心思。 ## 關於生產力的最後一點想法 如果你像我一樣喜歡閱讀有關心理學和生產力的文章,這是一篇很棒的文章 https://jamesclear.com/focus#Focus%20on%20the%20Process

7 個可以刺激網頁設計靈感的好地方:設計師、開發者推薦

身為開發者或設計師,要常常了解最新的設計趨勢,才能保持競爭力。 這邊有七個可以看到很多設計、刺激設計靈感的好地方,與您分享。 原文出處:https://dev.to/mohsenkamrani/7-websites-to-get-inspiration-for-next-level-web-design-1leg --- ## 1. https://dribbble.com 設計師社群分享網站。可以提供各種登陸頁面的設計靈感。 優點: 一個龐大而活躍的社群,大量設計可參考。 缺點:某些設計可能過於複雜或難以複製。 ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1670546361467/au1-ZogHe.png) ## 2. https://www.awwwards.com/ 展示來自世界各地的最佳設計,包括許多創意和有效的登錄頁面設計。 優點:高品質的設計,注重用戶體驗。 缺點:可能不像其他靈感來源那樣多樣化。 ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1670546444885/yExBAkGov.png) ## 3. https://www.behance.net/ 具有一系列設計組合,包括許多高品質登陸頁面的設計範例。 優點:含有大量設計稿,方便瀏覽和搜尋。 缺點:可能不像其他靈感來源那樣專注於登陸頁面。 ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1670546543511/RnNYQQKjG.png) ## 4. https://onepagelove.com/ 一個專門的網站,有很多啟發性的單頁設計,包括許多登陸頁面範例。 優點:專注於單頁設計,易於瀏覽和搜尋。 缺點:可能沒有其他靈感來源那麼多的多樣性。 ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1670546719953/9H4TBCmh8.png) ## 5. https://www.landingfolio.com/ 集合了網路上的最佳登陸頁面設計,為設計師提供豐富的靈感。 優點:大量高品質的設計,易於瀏覽和搜尋。 缺點:可能沒有其他靈感來源那麼多的多樣性。 ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1670546787563/o3nKNVT7C.png) ## 6. https://uxplanet.org/ 一個專注於使用者體驗設計的網站,包含許多精心設計的登錄頁面範例。 優點:注重用戶體驗,設計風格廣泛。 缺點:可能沒有其他靈感來源那麼多的設計。 ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1670546884319/oxqguR2Nz.png) ## 7. https://www.siteinspire.com/ 網頁設計靈感的精選集合,許多有效登錄頁面的範例。 優點:大量高品質的設計,易於瀏覽和搜尋。 缺點:可能沒有其他靈感來源那麼多的多樣性。 ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1670546938441/lXC_X5Dym.png) --- 希望您喜歡此清單,並使用它來為您的下一個專案獲得靈感。

寫出更好 JavaScript 的幾個實務技巧:新手推薦

JavaScript 寫起來有很大彈性,但如何改善自己的 JavaScript 品質呢?以下是一份實用的參考指南。 - 原文出處:https://dev.to/taillogs/practical-ways-to-write-better-javascript-26d4 # 使用 TypeScript 改善 JS 的第一個技巧就是,不要寫 JS。寫 TypeScript 吧。它是微軟寫的一個語言,算是 JS 的母集合(一般的 JS 可以直接在 TS 裡面跑)。TS 在 JS 之上添加了一個全面的型別系統。長期下來,整個前端生態系,幾乎都支援 TS 語言了。下面介紹一下 TS 的優點。 **TypeScript 可以確保「型別安全」** 型別安全代表編譯器驗證了所有型別是否以「合法」的方式被使用。換句話說,如果你創建一個接受「數字」的函數 `foo`: ``` function foo(someNum: number): number { return someNum + 5; } ``` 該「foo」函數呼叫時要傳一個數字: 正確用法 ``` console.log(foo(2)); // prints "7" ``` 錯誤用法 ``` console.log(foo("two")); // invalid TS code ``` 除了需要花時間加型別以外,沒有其他缺點了。好處則是顯而易見。型別安全針對常見錯誤提供了額外預防,這對於像 JS 這樣鬆散的語言來說,是一件好事。 **TypeScript 的型別系統,讓你能重構大型應用程式** 重構大型 JS 應用程式是一場噩夢。主要是因為它不會檢查函數簽名。也就是說,JS函數隨便呼叫,編譯器都不會先報錯。舉個例,如果我有一個函數「myAPI」,由 1000 個不同的服務使用: ``` function myAPI(someNum, someString) { if (someNum > 0) { leakCredentials(); } else { console.log(someString); } } ``` 我稍微更改了呼叫簽名: ``` function myAPI(someString, someNum) { if (someNum > 0) { leakCredentials(); } else { console.log(someString); } } ``` 我必須自已 100% 去確認,使用此功能的1000 個地方,都有正確更新用法。漏掉的地方,在執行時就會壞掉。在 TS 中相同的情境如下: before ``` function myAPITS(someNum: number, someString: string) { ... } ``` after ``` function myAPITS(someString: string, someNum: number) { ... } ``` 如您所見,「myAPITS」函數跟在 JavaScript 中一樣修改。但是,這段程式碼無法順利產出 JavaScript,而是會出現無效 TypeScript 的錯誤提示,因為用到它的1000個地方,現在型別就出錯了。正是因為「型別安全」,這 1000 個案例會阻止編譯。 **TypeScript 使團隊溝通架構更容易** 正確設定 TS 後,要先定義介面跟類型,不然很難寫程式碼。這也順便提供了一種簡潔、可溝通的架構提案方法。例如,如果我想跟後端提出新的「請求」類型,可以使用 TS 將以下內容提交給團隊。 ``` interface BasicRequest { body: Buffer; headers: { [header: string]: string | string[] | undefined; }; secret: Shhh; } ``` 雖然也是要寫一點程式碼,但可以先提供以上內容作為初步想法、取得回饋,而不用一次設計完功能。像這樣強迫開發者先定義介面跟 API,能讓程式碼品質更好。 總體而言,TS 已經發展成為一種成熟且更可預測的 vanilla JS 替代品。當然還是要熟 JS,但我現在大多數新專案都是直接寫 TS。 # 使用現代功能 JavaScript是世界上最流行的程式設計語言之一。你可能會以為這語言已經被百萬開發者摸透了,其實不是。很多新功能是近期才加上去的。 **`async` 與 `await`** 長期以來,非同步、事件驅動的 callback 是 JS 開發中不可避免的: 傳統 callback ``` makeHttpRequest('google.com', function (err, result) { if (err) { console.log('Oh boy, an error'); } else { console.log(result); } }); ``` 上述程式碼會有越寫越多層的問題。JS 添加了一個新概念叫 Promises,可以避免嵌套問題。 Promises ``` makeHttpRequest('google.com').then(function (result) { console.log(result); }).catch(function (err) { console.log('Oh boy, an error'); }); ``` 與 callback 相比,Promise 的最大優勢是可讀性和可鏈性。 雖然 Promise 很棒,但它們仍然有一些不足之處。寫起來感覺有點怪。為了解決這個問題,ECMAScript 委員會添加一種使用 promise 的新方法,`async` 和 `await`: `async` 與 `await` ``` try { const result = await makeHttpRequest('google.com'); console.log(result); } catch (err) { console.log('Oh boy, an error'); } ``` 需要注意的是,`await` 的內容必須先被宣告為 `async`: 以前面 makeHttpRequest 舉例 ``` async function makeHttpRequest(url) { // ... } ``` 也可以直接 `await` 一個 Promise,因為 `async` 函數實際上只是 Promise 比較花哨的包裝寫法。這也意味著,`async/await` 代碼和 Promise 代碼在功能上是等價的。因此,請大方使用 `async/await` 吧。 **`let` and `const`** 以前大家寫 JS 都只能用 `var`。`var` 的變數作用域有一些獨特規則,一直讓人很困惑。從 ES6 開始,有了 `const` 跟 `let` 可以替代使用,幾乎不用再寫 `var` 了。 至於何時要用 const 何時要用 let 呢?永遠從 const 先開始使用。const 因為不可修改、更可預期,會讓程式碼品質更好。使用 let 的場景比較少,我寫 const 的頻率比 let 高 20 倍左右。 **箭頭 `=>` 函數** 箭頭函數是在JS中宣告匿名函數的簡潔方法。通常作為 callback 或 event hook 傳遞。 傳統的匿名 function ``` someMethod(1, function () { // has no name console.log('called'); }); ``` 在大多數情況下,這種風格沒有任何“不對”。但它的變數作用域很“有趣”,常導致許多意想不到的錯誤。有了箭頭函數之後,就沒這問題了。 匿名箭頭函數 ``` someMethod(1, () => { // has no name console.log('called'); }); ``` 除了更簡潔之外,箭頭函數還具有更實用的變數範圍界定。箭頭函數從定義它們的作用域繼承「this」。 在某些情況下,箭頭函數甚至可以更簡潔: ``` const added = [0, 1, 2, 3, 4].map((item) => item + 1); console.log(added) // prints "[1, 2, 3, 4, 5]" ``` 箭頭函數可以包括隱式的「return」語句。就不用寫大括弧、分號。 不過,這跟“var”被完全取代不同。傳統匿名函數仍然有需要的地方,例如類別方法定義。話雖如此,如果你總是預設使用箭頭函數,程式碼錯誤會少很多。 **展開運算子 `...`** 提取一個物件的鍵/值對,並將它們添加為另一個物件的子物件,是一種很常見的場景。從歷史上看,有幾種方法可以實現,但通通都很笨拙: ``` const obj1 = { dog: 'woof' }; const obj2 = { cat: 'meow' }; const merged = Object.assign({}, obj1, obj2); console.log(merged) // prints { dog: 'woof', cat: 'meow' } ``` 這寫法以前很常見,也很囉唆。多虧了「展開運算子」,再也不需要那樣寫了: ``` const obj1 = { dog: 'woof' }; const obj2 = { cat: 'meow' }; console.log({ ...obj1, ...obj2 }); // prints { dog: 'woof', cat: 'meow' } ``` 最棒的是,與陣列也可無縫接軌: ``` const arr1 = [1, 2]; const arr2 = [3, 4]; console.log([ ...arr1, ...arr2 ]); // prints [1, 2, 3, 4] ``` 它可能不是近期 JS 中最重要的功能,但它是我的最愛之一。 **範本文字(範本字串)** 字串處理太常見了,程式語言要能處理範本字串,才夠好用。處理動態內容、多行文字時,都會需要它: ``` const name = 'Ryland'; const helloString = `Hello ${name}`; ``` 我認為程式碼不言自明。看起來好多了。 **物件解構** 物件解構是一種從資料集合(物件、陣列等)中提取值,而無需反覆運算數據或顯式訪問其鍵的方法: 老方法 ``` function animalParty(dogSound, catSound) {} const myDict = { dog: 'woof', cat: 'meow', }; animalParty(myDict.dog, myDict.cat); ``` 新方法 ``` function animalParty(dogSound, catSound) {} const myDict = { dog: 'woof', cat: 'meow', }; const { dog, cat } = myDict; animalParty(dog, cat); ``` 不只這樣。您還可以在函數的簽名中定義解構: 解構範例二 ``` function animalParty({ dog, cat }) {} const myDict = { dog: 'woof', cat: 'meow', }; animalParty(myDict); ``` 它也適用於陣列: 解構範例三 ``` [a, b] = [10, 20]; console.log(a); // prints 10 ``` --- 以上,希望對您有幫助!

快速複習 React 基本觀念&實務範例:推薦新手參考

React 作為一個強大的前端工具,有很多需要熟悉的基本觀念&語法。 這篇文章做一個快速的全面整理,方便工作時,可以隨時翻閱,希望您喜歡。 - 原文出處:https://dev.to/reedbarger/the-react-cheatsheet-for-2020-real-world-examples-4hgg ## 核心概念 ### 元素和 JSX - React 元素的基本語法 ``` // In a nutshell, JSX allows us to write HTML in our JS // JSX can use any valid html tags (i.e. div/span, h1-h6, form/input, etc) <div>Hello React</div> ``` - JSX 元素就是一段表達式 ``` // as an expression, JSX can be assigned to variables... const greeting = <div>Hello React</div>; const isNewToReact = true; // ... or can be displayed conditionally function sayGreeting() { if (isNewToReact) { // ... or returned from functions, etc. return greeting; // displays: Hello React } else { return <div>Hi again, React</div>; } } ``` - JSX 允許我們嵌套表達式 ``` const year = 2020; // we can insert primitive JS values in curly braces: {} const greeting = <div>Hello React in {year}</div>; // trying to insert objects will result in an error ``` - JSX 允許我們嵌套元素 ``` // to write JSX on multiple lines, wrap in parentheses: () const greeting = ( // div is the parent element <div> {/* h1 and p are child elements */} <h1>Hello!</h1> <p>Welcome to React</p> </div> ); // 'parents' and 'children' are how we describe JSX elements in relation // to one another, like we would talk about HTML elements ``` - HTML 和 JSX 的語法略有不同 ``` // Empty div is not <div></div> (HTML), but <div/> (JSX) <div/> // A single tag element like input is not <input> (HTML), but <input/> (JSX) <input name="email" /> // Attributes are written in camelcase for JSX (like JS variables <button className="submit-button">Submit</button> // not 'class' (HTML) ``` - 最基本的 React 應用程式需要三樣東西: - 1. ReactDOM.render() 渲染我們的應用程序 - 2. 一個 JSX 元素(在此情況下,稱為根節點) - 3. 一個用於掛載應用程式的 DOM 元素(通常是 index.html 文件中 id 為 root 的 div) ``` // imports needed if using NPM package; not if from CDN links import React from "react"; import ReactDOM from "react-dom"; const greeting = <h1>Hello React</h1>; // ReactDOM.render(root node, mounting point) ReactDOM.render(greeting, document.getElementById("root")); ``` ### 元件和 Props - 基本 React 元件的語法 ``` import React from "react"; // 1st component type: function component function Header() { // function components must be capitalized unlike normal JS functions // note the capitalized name here: 'Header' return <h1>Hello React</h1>; } // function components with arrow functions are also valid const Header = () => <h1>Hello React</h1>; // 2nd component type: class component // (classes are another type of function) class Header extends React.Component { // class components have more boilerplate (with extends and render method) render() { return <h1>Hello React</h1>; } } ``` - 如何使用元件 ``` // do we call these function components like normal functions? // No, to execute them and display the JSX they return... const Header = () => <h1>Hello React</h1>; // ...we use them as 'custom' JSX elements ReactDOM.render(<Header />, document.getElementById("root")); // renders: <h1>Hello React</h1> ``` - 元件可以在我們的應用程式中重複使用 ``` // for example, this Header component can be reused in any app page // this component shown for the '/' route function IndexPage() { return ( <div> <Header /> <Hero /> <Footer /> </div> ); } // shown for the '/about' route function AboutPage() { return ( <div> <Header /> <About /> <Testimonials /> <Footer /> </div> ); } ``` - 資料可以通過 props 動態傳遞給元件 ``` // What if we want to pass data to our component from a parent? // I.e. to pass a user's name to display in our Header? const username = "John"; // we add custom 'attributes' called props ReactDOM.render( <Header username={username} />, document.getElementById("root") ); // we called this prop 'username', but can use any valid JS identifier // props is the object that every component receives as an argument function Header(props) { // the props we make on the component (i.e. username) // become properties on the props object return <h1>Hello {props.username}</h1>; } ``` - Props 不可直接改變(mutate) ``` // Components must ideally be 'pure' functions. // That is, for every input, we be able to expect the same output // we cannot do the following with props: function Header(props) { // we cannot mutate the props object, we can only read from it props.username = "Doug"; return <h1>Hello {props.username}</h1>; } // But what if we want to modify a prop value that comes in? // That's where we would use state (see the useState section) ``` - 如果我們想將元素/元件作為 props 傳遞給其它元件,可以用 children props ``` // Can we accept React elements (or components) as props? // Yes, through a special property on the props object called 'children' function Layout(props) { return <div className="container">{props.children}</div>; } // The children prop is very useful for when you want the same // component (such as a Layout component) to wrap all other components: function IndexPage() { return ( <Layout> <Header /> <Hero /> <Footer /> </Layout> ); } // different page, but uses same Layout component (thanks to children prop) function AboutPage() { return ( <Layout> <About /> <Footer /> </Layout> ); } ``` - 可以用三元運算子來條件顯示元件 ``` // if-statements are fine to conditionally show , however... // ...only ternaries (seen below) allow us to insert these conditionals // in JSX, however function Header() { const isAuthenticated = checkAuth(); return ( <nav> <Logo /> {/* if isAuth is true, show AuthLinks. If false, Login */} {isAuthenticated ? <AuthLinks /> : <Login />} {/* if isAuth is true, show Greeting. If false, nothing. */} {isAuthenticated && <Greeting />} </nav> ); } ``` - Fragments 是用來顯示多個元件的特殊元件,無需向 DOM 添加額外的元素 - Fragments 適合用在條件邏輯 ``` // we can improve the logic in the previous example // if isAuthenticated is true, how do we display both AuthLinks and Greeting? function Header() { const isAuthenticated = checkAuth(); return ( <nav> <Logo /> {/* we can render both components with a fragment */} {/* fragments are very concise: <> </> */} {isAuthenticated ? ( <> <AuthLinks /> <Greeting /> </> ) : ( <Login /> )} </nav> ); } ``` ### 列表和 keys - 使用 .map() 將資料列表(陣列)轉換為元素列表 ``` const people = ["John", "Bob", "Fred"]; const peopleList = people.map(person => <p>{person}</p>); ``` - .map() 也可用來轉換為元件列表 ``` function App() { const people = ['John', 'Bob', 'Fred']; // can interpolate returned list of elements in {} return ( <ul> {/* we're passing each array element as props */} {people.map(person => <Person name={person} />} </ul> ); } function Person({ name }) { // gets 'name' prop using object destructuring return <p>this person's name is: {name}</p>; } ``` - 迭代的每個 React 元素都需要一個特殊的 `key` prop - key 對於 React 來說是必須的,以便能夠追蹤每個正在用 map 迭代的元素 - 沒有 key,當資料改變時,React 較難弄清楚元素應該如何更新 - key 應該是唯一值,才能讓 React 知道如何分辨 ``` function App() { const people = ['John', 'Bob', 'Fred']; return ( <ul> {/* keys need to be primitive values, ideally a generated id */} {people.map(person => <Person key={person} name={person} />)} </ul> ); } // If you don't have ids with your set of data or unique primitive values, // you can use the second parameter of .map() to get each elements index function App() { const people = ['John', 'Bob', 'Fred']; return ( <ul> {/* use array element index for key */} {people.map((person, i) => <Person key={i} name={person} />)} </ul> ); } ``` ### 事件和事件處理器 - React 和 HTML 中的事件略有不同 ``` // Note: most event handler functions start with 'handle' function handleToggleTheme() { // code to toggle app theme } // in html, onclick is all lowercase <button onclick="handleToggleTheme()"> Submit </button> // in JSX, onClick is camelcase, like attributes / props // we also pass a reference to the function with curly braces <button onClick={handleToggleTheme}> Submit </button> ``` - 最該先學的 React 事件是 onClick 和 onChange - onClick 處理 JSX 元素上的點擊事件(也就是按鈕動作) - onChange 處理鍵盤事件(也就是打字動作) ``` function App() { function handleChange(event) { // when passing the function to an event handler, like onChange // we get access to data about the event (an object) const inputText = event.target.value; const inputName = event.target.name; // myInput // we get the text typed in and other data from event.target } function handleSubmit() { // on click doesn't usually need event data } return ( <div> <input type="text" name="myInput" onChange={handleChange} /> <button onClick={handleSubmit}>Submit</button> </div> ); } ``` ## React Hooks ### State and useState - useState 為我們提供 function component 中的本地狀態 ``` import React from 'react'; // create state variable // syntax: const [stateVariable] = React.useState(defaultValue); function App() { const [language] = React.useState('javascript'); // we use array destructuring to declare state variable return <div>I am learning {language}</div>; } ``` - 注意:此段文章中的任何 hook 都來自 React 套件,且可以單獨導入 ``` import React, { useState } from "react"; function App() { const [language] = useState("javascript"); return <div>I am learning {language}</div>; } ``` - useState 還為我們提供了一個 `setter` 函數來更新它的狀態 ``` function App() { // the setter function is always the second destructured value const [language, setLanguage] = React.useState("python"); // the convention for the setter name is 'setStateVariable' return ( <div> {/* why use an arrow function here instead onClick={setterFn()} ? */} <button onClick={() => setLanguage("javascript")}> Change language to JS </button> {/* if not, setLanguage would be called immediately and not on click */} <p>I am now learning {language}</p> </div> ); } // note that whenever the setter function is called, the state updates, // and the App component re-renders to display the new state ``` - useState 可以在單個元件中使用一次或多次 ``` function App() { const [language, setLanguage] = React.useState("python"); const [yearsExperience, setYearsExperience] = React.useState(0); return ( <div> <button onClick={() => setLanguage("javascript")}> Change language to JS </button> <input type="number" value={yearsExperience} onChange={event => setYearsExperience(event.target.value)} /> <p>I am now learning {language}</p> <p>I have {yearsExperience} years of experience</p> </div> ); } ``` - useState 可以接受 primitive value 或物件 ``` // we have the option to organize state using whatever is the // most appropriate data type, according to the data we're tracking function App() { const [developer, setDeveloper] = React.useState({ language: "", yearsExperience: 0 }); function handleChangeYearsExperience(event) { const years = event.target.value; // we must pass in the previous state object we had with the spread operator setDeveloper({ ...developer, yearsExperience: years }); } return ( <div> {/* no need to get prev state here; we are replacing the entire object */} <button onClick={() => setDeveloper({ language: "javascript", yearsExperience: 0 }) } > Change language to JS </button> {/* we can also pass a reference to the function */} <input type="number" value={developer.yearsExperience} onChange={handleChangeYearsExperience} /> <p>I am now learning {developer.language}</p> <p>I have {developer.yearsExperience} years of experience</p> </div> ); } ``` - 如果新狀態依賴於之前的狀態,我們可以在 setter 函數中使用一個函數來為我們提供之前狀態的值 ``` function App() { const [developer, setDeveloper] = React.useState({ language: "", yearsExperience: 0, isEmployed: false }); function handleToggleEmployment(event) { // we get the previous state variable's value in the parameters // we can name 'prevState' however we like setDeveloper(prevState => { return { ...prevState, isEmployed: !prevState.isEmployed }; // it is essential to return the new state from this function }); } return ( <button onClick={handleToggleEmployment}>Toggle Employment Status</button> ); } ``` ### side effects 和 useEffect - useEffect 讓我們在 function component 中執行副作用。什麼是副作用? - 副作用是我們需要接觸外部世界的地方。例如,從 API 獲取資料或操作 DOM。 - 副作用是可能以不可預測的方式,改變我們元件狀態的操作(導致「副作用」)。 - useEffect 接受 callback function(稱為 effect 函數),預設情況下,每次重新渲染時都會運行 - useEffect 在我們的元件載入後運行,可以準確在元件的各個生命週期觸發 ``` // what does our code do? Picks a color from the colors array // and makes it the background color function App() { const [colorIndex, setColorIndex] = React.useState(0); const colors = ["blue", "green", "red", "orange"]; // we are performing a 'side effect' since we are working with an API // we are working with the DOM, a browser API outside of React useEffect(() => { document.body.style.backgroundColor = colors[colorIndex]; }); // whenever state is updated, App re-renders and useEffect runs function handleChangeIndex() { const next = colorIndex + 1 === colors.length ? 0 : colorIndex + 1; setColorIndex(next); } return <button onClick={handleChangeIndex}>Change background color</button>; } ``` - 如果不想在每次渲染後都執行 callback function,可以在第二個參數傳一個空陣列 ``` function App() { ... // now our button doesn't work no matter how many times we click it... useEffect(() => { document.body.style.backgroundColor = colors[colorIndex]; }, []); // the background color is only set once, upon mount // how do we not have the effect function run for every state update... // but still have it work whenever the button is clicked? return ( <button onClick={handleChangeIndex}> Change background color </button> ); } ``` - useEffect 讓我們能夠在 dependencies 陣列的內容改變時,才執行 - dependencies 陣列是第二個參數,如果陣列中的任何一個值發生變化,effect function 將再次運行 ``` function App() { const [colorIndex, setColorIndex] = React.useState(0); const colors = ["blue", "green", "red", "orange"]; // we add colorIndex to our dependencies array // when colorIndex changes, useEffect will execute the effect fn again useEffect(() => { document.body.style.backgroundColor = colors[colorIndex]; // when we use useEffect, we must think about what state values // we want our side effect to sync with }, [colorIndex]); function handleChangeIndex() { const next = colorIndex + 1 === colors.length ? 0 : colorIndex + 1; setColorIndex(next); } return <button onClick={handleChangeIndex}>Change background color</button>; } ``` - 可以在 useEffect 最後回傳一個函數,來取消訂閱某些效果 ``` function MouseTracker() { const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); React.useEffect(() => { // .addEventListener() sets up an active listener... window.addEventListener("mousemove", handleMouseMove); // ...so when we navigate away from this page, it needs to be // removed to stop listening. Otherwise, it will try to set // state in a component that doesn't exist (causing an error) // We unsubscribe any subscriptions / listeners w/ this 'cleanup function' return () => { window.removeEventListener("mousemove", handleMouseMove); }; }, []); function handleMouseMove(event) { setMousePosition({ x: event.pageX, y: event.pageY }); } return ( <div> <h1>The current mouse position is:</h1> <p> X: {mousePosition.x}, Y: {mousePosition.y} </p> </div> ); } // Note: we could extract the reused logic in the callbacks to // their own function, but I believe this is more readable ``` - 使用 useEffect 撈取資料 - 請注意,如果要使用更簡潔的 async/awit 語法處理 promise,則需要建立一個單獨的函數(因為 effect callback function 不能是 async) ``` const endpoint = "https://api.github.com/users/codeartistryio"; // with promises: function App() { const [user, setUser] = React.useState(null); React.useEffect(() => { // promises work in callback fetch(endpoint) .then(response => response.json()) .then(data => setUser(data)); }, []); } // with async / await syntax for promise: function App() { const [user, setUser] = React.useState(null); // cannot make useEffect callback function async React.useEffect(() => { getUser(); }, []); // instead, use async / await in separate function, then call // function back in useEffect async function getUser() { const response = await fetch("https://api.github.com/codeartistryio"); const data = await response.json(); setUser(data); } } ``` ### 效能和 useCallback - useCallback 是一個用來提高元件性能的 hook - 如果你有一個經常重新渲染的元件,useCallback 可以防止元件內的 callback function 在每次元件重新渲染時都重新創建(導致元件重新運行) - useCallback 僅在其依賴項之一改變時重新運行 ``` // in Timer, we are calculating the date and putting it in state a lot // this results in a re-render for every state update // we had a function handleIncrementCount to increment the state 'count'... function Timer() { const [time, setTime] = React.useState(); const [count, setCount] = React.useState(0); // ... but unless we wrap it in useCallback, the function is // recreated for every single re-render (bad performance hit) // useCallback hook returns a callback that isn't recreated every time const inc = React.useCallback( function handleIncrementCount() { setCount(prevCount => prevCount + 1); }, // useCallback accepts a second arg of a dependencies array like useEffect // useCallback will only run if any dependency changes (here it's 'setCount') [setCount] ); React.useEffect(() => { const timeout = setTimeout(() => { const currentTime = JSON.stringify(new Date(Date.now())); setTime(currentTime); }, 300); return () => { clearTimeout(timeout); }; }, [time]); return ( <div> <p>The current time is: {time}</p> <p>Count: {count}</p> <button onClick={inc}>+</button> </div> ); } ``` ### Memoization 和 useMemo - useMemo 和 useCallback 非常相似,都是為了提高效能。但就不是為了暫存 callback function,而是為了暫存耗費效能的運算結果 - useMemo 允許我們「記憶」已經為某些輸入進行了昂貴計算的結果(之後就不用重新計算了) - useMemo 從計算中回傳一個值,而不是 callback 函數(但可以是一個函數) ``` // useMemo is useful when we need a lot of computing resources // to perform an operation, but don't want to repeat it on each re-render function App() { // state to select a word in 'words' array below const [wordIndex, setWordIndex] = useState(0); // state for counter const [count, setCount] = useState(0); // words we'll use to calculate letter count const words = ["i", "am", "learning", "react"]; const word = words[wordIndex]; function getLetterCount(word) { // we mimic expensive calculation with a very long (unnecessary) loop let i = 0; while (i < 1000000) i++; return word.length; } // Memoize expensive function to return previous value if input was the same // only perform calculation if new word without a cached value const letterCount = React.useMemo(() => getLetterCount(word), [word]); // if calculation was done without useMemo, like so: // const letterCount = getLetterCount(word); // there would be a delay in updating the counter // we would have to wait for the expensive function to finish function handleChangeIndex() { // flip from one word in the array to the next const next = wordIndex + 1 === words.length ? 0 : wordIndex + 1; setWordIndex(next); } return ( <div> <p> {word} has {letterCount} letters </p> <button onClick={handleChangeIndex}>Next word</button> <p>Counter: {count}</p> <button onClick={() => setCount(count + 1)}>+</button> </div> ); } ``` ### Refs 和 useRef - Refs 是所有 React 組件都可用的特殊屬性。允許我們在元件安裝時,創建針對特定元素/元件的引用 - useRef 允許我們輕鬆使用 React refs - 我們在元件開頭呼叫 useRef,並將回傳值附加到元素的 ref 屬性來引用它 - 一旦我們創建了一個引用,就可以用它來改變元素的屬性,或者可以呼叫該元素上的任何可用方法(比如用 .focus() 來聚焦) ``` function App() { const [query, setQuery] = React.useState("react hooks"); // we can pass useRef a default value // we don't need it here, so we pass in null to ref an empty object const searchInput = useRef(null); function handleClearSearch() { // current references the text input once App mounts searchInput.current.value = ""; // useRef can store basically any value in its .current property searchInput.current.focus(); } return ( <form> <input type="text" onChange={event => setQuery(event.target.value)} ref={searchInput} /> <button type="submit">Search</button> <button type="button" onClick={handleClearSearch}> Clear </button> </form> ); } ``` ## 進階 Hook ### Context 和 useContext - 在 React 中,盡量避免創建多個 props 來將資料從父元件向下傳遞兩個或多個層級 ``` // Context helps us avoid creating multiple duplicate props // This pattern is also called props drilling: function App() { // we want to pass user data down to Header const [user] = React.useState({ name: "Fred" }); return ( // first 'user' prop <Main user={user} /> ); } const Main = ({ user }) => ( <> {/* second 'user' prop */} <Header user={user} /> <div>Main app content...</div> </> ); const Header = ({ user }) => <header>Welcome, {user.name}!</header>; ``` - Context 有助於將 props 從父組件向下傳遞到多個層級的子元件 ``` // Here is the previous example rewritten with Context // First we create context, where we can pass in default values const UserContext = React.createContext(); // we call this 'UserContext' because that's what data we're passing down function App() { // we want to pass user data down to Header const [user] = React.useState({ name: "Fred" }); return ( {/* we wrap the parent component with the provider property */} {/* we pass data down the computer tree w/ value prop */} <UserContext.Provider value={user}> <Main /> </UserContext.Provider> ); } const Main = () => ( <> <Header /> <div>Main app content...</div> </> ); // we can remove the two 'user' props, we can just use consumer // to consume the data where we need it const Header = () => ( {/* we use this pattern called render props to get access to the data*/} <UserContext.Consumer> {user => <header>Welcome, {user.name}!</header>} </UserContext.Consumer> ); ``` - useContext hook 可以移除這種看起來很怪的 props 渲染模式,同時又能在各種 function component 中隨意使用 ``` const Header = () => { // we pass in the entire context object to consume it const user = React.useContext(UserContext); // and we can remove the Consumer tags return <header>Welcome, {user.name}!</header>; }; ``` ### Reducers 和 useReducer - Reducers 是簡單、可預測的(純)函數,它接受一個先前的狀態物件和一個動作物件,並回傳一個新的狀態物件。例如: ``` // let's say this reducer manages user state in our app: function reducer(state, action) { // reducers often use a switch statement to update state // in one way or another based on the action's type property switch (action.type) { // if action.type has the string 'LOGIN' on it case "LOGIN": // we get data from the payload object on action return { username: action.payload.username, isAuth: true }; case "SIGNOUT": return { username: "", isAuth: false }; default: // if no case matches, return previous state return state; } } ``` - Reducers 是一種強大的狀態管理模式,用於流行的 Redux 狀態管理套件(這套很常與 React 一起使用) - 與 useState(用於本地元件狀態)相比,Reducers 可以通過 useReducer hook 在 React 中使用,以便管理我們應用程序的狀態 - useReducer 可以與 useContext 配對來管理資料並輕鬆地將資料傳遞給元件 - useReducer + useContext 可以當成應用程式的整套狀態管理系統 ``` const initialState = { username: "", isAuth: false }; function reducer(state, action) { switch (action.type) { case "LOGIN": return { username: action.payload.username, isAuth: true }; case "SIGNOUT": // could also spread in initialState here return { username: "", isAuth: false }; default: return state; } } function App() { // useReducer requires a reducer function to use and an initialState const [state, dispatch] = useReducer(reducer, initialState); // we get the current result of the reducer on 'state' // we use dispatch to 'dispatch' actions, to run our reducer // with the data it needs (the action object) function handleLogin() { dispatch({ type: "LOGIN", payload: { username: "Ted" } }); } function handleSignout() { dispatch({ type: "SIGNOUT" }); } return ( <> Current user: {state.username}, isAuthenticated: {state.isAuth} <button onClick={handleLogin}>Login</button> <button onClick={handleSignout}>Signout</button> </> ); } ``` ### 編寫 custom hooks - 創建 hook 就能輕鬆在元件之間重用某些行為 - hook 是一種比以前的 class component 更容易理解的模式,例如 higher-order components 或者 render props - 根據需要,隨時可以自創一些 hook ``` // here's a custom hook that is used to fetch data from an API function useAPI(endpoint) { const [value, setValue] = React.useState([]); React.useEffect(() => { getData(); }, []); async function getData() { const response = await fetch(endpoint); const data = await response.json(); setValue(data); }; return value; }; // this is a working example! try it yourself (i.e. in codesandbox.io) function App() { const todos = useAPI("https://todos-dsequjaojf.now.sh/todos"); return ( <ul> {todos.map(todo => <li key={todo.id}>{todo.text}</li>)} </ul> ); } ``` ### Hooks 規則 - 使用 React hooks 有兩個核心規則,要遵守才能正常運作: - 1. Hooks 只能在元件開頭呼叫 - Hooks 不能放在條件、迴圈或嵌套函數中 - 2. Hooks只能在 function component 內部使用 - Hooks 不能放在普通的 JavaScript 函數或 class component 中 ``` function checkAuth() { // Rule 2 Violated! Hooks cannot be used in normal functions, only components React.useEffect(() => { getUser(); }, []); } function App() { // this is the only validly executed hook in this component const [user, setUser] = React.useState(null); // Rule 1 violated! Hooks cannot be used within conditionals (or loops) if (!user) { React.useEffect(() => { setUser({ isAuth: false }); // if you want to conditionally execute an effect, use the // dependencies array for useEffect }, []); } checkAuth(); // Rule 1 violated! Hooks cannot be used in nested functions return <div onClick={() => React.useMemo(() => doStuff(), [])}>Our app</div>; } ``` --- 以上是快速整理,希望對您有幫助!

簡單介紹一下 NextJS 框架

Next.js 是一個開源、輕量的 JavaScript 框架。它讓您能用 React 開發高速又好用的 Web 應用程式與靜態網站。 這篇文章簡單介紹一下這個框架! - 原文出處:https://dev.to/documatic/why-use-nextjs-mn3 # 簡介 Next.js 是用來建造 server-side rendering 的 web 應用程式的 ReactJS 框架。包含很多現成功能,例如程式碼自動拆分、基於檔案的路由、hot reloading 和通用渲染。 https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0oqlfzpvx0rkns65juxt.png Next.js 會在 React 之外處理好工具、設定,並額外提供架構、功能、與效能優化。 Next.js 由 Vercel 的軟體工程師 Guillermo Rauch 打造,並由 Vercel 的開發團隊維護。它是一個開源專案,可以在 GitHub 上找到程式碼。 # Next.js 是做什麼用的? Next.JS 常用來建造以下類型的網站: - 電子商務網站 - 部落格 - 投資組合網站 - 文件網站 - 行銷網站等等 # Next.js 和 React.js 的區別 Next.js 和 React 都是建造 Web 應用程式的常用工具。但是,它們之間有明顯差異,適用不同場景。以下分別討論幾點: # 效能 性能是 Next.js 和 React.js 之間的主要區別。 Next.js 內建許多效能優化,例如圖像優化。這些優化使 Next.js 網站跑起來非常快。 另一方面,ReactJS 是在客戶端渲染,對於高性能應用程式來說,就不太夠力。 # SEO 靜態網站比較適合 SEO 優化,使用 Next.js 很容易做出靜態網站。SEO 越好,在搜尋結果越前面。 而 React 因為是渲染 singe page application,對 SEO 來說就比較吃虧。 # Server-side rendering Next.js 提供伺服器端渲染功能 (SSR)。當您需要為不同用戶提供不同渲染方式,它可以撈資料然後回應不同請求。 雖然可以啟用,但 React 預設不支援伺服器端渲染。SSR 可以與一些伺服器軟體整合,但需要一些額外作業。 # 開發者社群 React 社群很活躍、資源很多。 Next.js 大部份討論都在 GitHub 上面。 React.JS 和 Next.JS 都有很好的開發者體驗。 # 設定檔 使用 Create React App 的話,記得要跳出來才能獨立設定各項設定檔。 使用 Next.js 的話,可以在 Next.js 模板直接自訂 `babelrc`、`jest.config` 和 `eslintrc` 等文件。 # 結論 簡單介紹一下 Next.js ,希望對您有幫助!