🔍 搜尋結果:生命

🔍 搜尋結果:生命

簡化複雜 - 深入探討 Kubernetes 元件

## 介紹 幾天前,我在我曾經就讀的大學舉辦了一場關於 Kubernetes 及其元件的演講。我媽媽說她喜歡這個演講,所以我把它變成了一篇部落格文章。 許多軟體工程師傾向於忽視與 Kubernetes 相關的任何東西,儘管他們可能每天都會使用它。乍一看,它似乎很複雜,就像一個需要潛入的全新世界。是的,確實如此,但在這篇文章中,我將介紹 Kubernetes 叢集的所有主要元件,並在範例中解釋它們的作用。 在這篇文章結束時,您不會成為 Kubernetes 專家,但您可能會很好地了解要尋找什麼以及如何建立 Kubernetes 最初看起來的混亂狀態。 *代表 Kubernetes 架構的圖片取自 [Kubernetes 網站](https://kubernetes.io/docs/concepts/overview/components/)* ### **向我們展示您的支持🙏🏻** ![Github 明星](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mab4sx5zugkc89ac7h4l.gif) 在我們開始之前,如果您為我們的儲存庫加註星標並幫助我們在其他開發人員面前獲得我們的工具,我們將非常高興。我們的 GitHub 儲存庫位於:https://github.com/cyclops-ui/cyclops ⭐ ## 成分 首先,我們可以將 Kubernetes 叢集分為兩部分:**控制平面**和**工作節點**。控制平面負責整個操作並控制集群的狀態。我們很快就會了解這意味著什麼。另一方面,我們的工作節點本質上只是監聽控制平面告訴它們要做什麼的電腦。它們是我們集群的運算能力。我們在叢集中執行的任何應用程式都將在這些節點上執行。 讓我們進一步分解。 ### 控制平面 ![控制平面](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdy560pic4ae8ilelh58.png) 正如我們所說,控制平面確保我們的叢集能如預期運作。它透過與叢集用戶通訊、調度工作負載、管理叢集狀態等來實現這一點。 控制平面由四個關鍵元件組成。它們本身很簡單,但一起建立了一個複雜的系統。這些元件是: - **API** - **ETCD** - **調度程序** - **控制器經理** 控制平面元件可以在叢集中的任何機器上執行,但通常在一組單獨的機器上執行,通常稱為**主節點**。這些機器不用於執行任何其他容器或應用程式,而是為 Kubernetes 控制平面保留。 #### API Kubernetes API 充當叢集的前端接口,允許使用者與叢集互動、定義所需狀態以及執行建立、更新和刪除資源等操作。 這是我們與集群的**唯一聯繫點**。此外,沒有其他元件直接相互通信,但所有通信都是透過 API 進行的。 #### ETCD ETCD 是 API 的**資料庫**;就這麼簡單。當您告訴 Kubernetes 建立部署時,它會與所有其他建立的資源一起儲存在 ETCD 中。 ETCD 的一個特點是它的鍵值儲存被組織為檔案系統。 ETCD 的另一個出色功能是用戶可以**訂閱**事件並獲得有關更改的通知。例如,*建立新 Pod 時讓我知道*。 #### 調度程序 顧名思義,調度程式**決定 pod 將在哪個節點上執行**。它透過一組規則來實現這一點,您可以在 [Kubernetes 文件](https://kubernetes.io/docs/home/) 中閱讀。 *這就是我說你不會成為專家時的意思,但你會知道要谷歌什麼:)* 調度程序**訂閱**保存在 ETCD 中的所有新建立的 pod,但它**只能**與 API 通訊來取得此更新。 當它發現 Pod 已建立時,它會計算在哪個工作節點上執行它。一旦決定,**調度程序不會在任何機器上執行任何東西**;它只是告訴 API 在特定節點上執行 pod。 #### 控制器管理器 控制平面的最後一個元件是控制器管理器。我們可以把它當作我們集群的恆溫器。它的工作是將集群的當前狀態轉變為所需的狀態。 這意味著它將**在幕後建立所有需要的資源**來滿足我們的需求並使我們的應用程式啟動並執行。 它執行多個控制器進程,這些進程訂閱了 ETCD 上的更改,並編譯成相同的二進位檔案以便於部署。控制器管理員的角色以及這些控制器的作用將在部落格後面進行更詳細的定義。 ### 工作節點 ![工作節點](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gz5ocd4ito4o0n7fjzct.png) 現在我們已經了解了整個叢集的管理方式,接下來讓我們深入了解容器在哪裡運作以及如何實現這一點。 Kubernetes 叢集中的每個節點上執行 3 個元件。當然,您可以在叢集中擁有多個節點,但每個節點都需要這三個元件來託管您的應用程式。 那些是: - **容器運作時** - **kubelet** - **成為代理** #### 容器執行時 允許 Kubernetes 執行容器並管理節點上容器的生命週期的元件是容器執行時。 支援多個容器執行時,例如[conatinerd](https://containerd.io/)、[cri-o](https://cri-o.io/) 或其他[CRI 相容執行時](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md)。 #### 庫貝萊特 另一個訂閱 pod 事件的元件是 Kubelet。每次在節點上調度 pod 時,該節點上執行的 Kubelet 都會聽到該訊息並啟動所有定義的容器。最重要的是,Kubelet 還執行健康檢查,以確保一切能如預期運作。 #### 成為代理 Kubernetes 中的 KubeProxy 管理叢集中 pod 之間的網路連接,處理負載平衡和網路路由等任務。它透過維護網路規則並將服務抽象轉換為可操作的網路策略來確保 Pod 之間的無縫通訊。 ## 從部署到正在執行的容器 現在我們已經列出了 Kubernetes 叢集中的所有元件及其角色,接下來讓我們講述一個有關 Kubernetes 部署如何成為在叢集中的各種電腦上執行的一組容器的故事。 ### Pod、副本集和部署 快速提醒這三者的關係:Pod、Replicaset 和 Deployment。 ![部署元件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cs9u7fnhe3q096bkyp2l.png) 我們可以在 Kubernetes 叢集中部署的最小單元是 **pod**。有了它,我們將定義我們的容器。 最有可能的是,我們需要同一應用程式的幾個實例,並且我們可以定義如何使用 **Replicaset** 複製我們的 pod。它將透過啟動和終止來確保我們有所需數量的 Pod 執行。 太棒了,現在我們已經複製了我們的應用程式,但我們想推出新版本的應用程式。我們必須拆除現有的 Pod/Replicaset 並建立新的。部署將自動執行此流程,使我們能夠安全地推出我們的功能。 ## 威望 ![聲望](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yyxboeqedu4yvg0ceg29.gif) 現在我們已經了解了所有術語並觸及了所有 Kubernetes 元件及其角色,讓我們看看當我們將 Deployment「套用」到 Kubernetes 叢集時會發生什麼。 假設我們已經建立了一個定義應用程式的「deployment.yaml」檔案(您可以在[此處](https://imgur.com/7qKp189)了解如何執行此操作)並執行「kubectl apply -f deployment. yaml” 。 `kubectl` 現在將把我們的部署定義提交到叢集的**唯一的聯絡點** - Kubernetes API。 我們的簡單 API 將把我們的部署儲存在 ETCD 資料庫中。每次將 Deployment 物件儲存到 ETCD 時,它都會讓 API 知道 Deployments 發生了更改,並且它應該讓**每個訂閱此類事件的人**知道這一點。 控制平面中有一個元件想要知道何時產生新的部署,這就是**控制器管理器**。當它聽到新的 Deployment 時,它將根據 Deployment 配置建立一個新的 Replicaset。為了建立此 Replicaset,它將透過建立請求來呼叫 API。 建立 Replicaset 與建立 Deployment 非常相似。 API 將接收一個 Replicaset 來建立並儲存到 ETCD 中。這將使 ETCD 告訴 API 有人建立了一個 Replicaset 並將該資訊傳遞給所有訂閱的元件,這又是控制器管理器。 當 Controller Manager 聽到新的 Replicaset 時,它會透過呼叫 API 來建立使用該 Replicaset 定義的所有 Pod,您猜對了,該 API 會將所有這些 Pod 儲存到 ETCD 中。 ![k8s_deployment_gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c6d97k6rggdrbbwes7d9.gif) *正如我們所說,發生了很多事情,因此我們決定建立一個 GIF 來幫助您了解整個過程。* 在這裡,我們包括了 Scheduler,它訂閱了 Pod 建立事件。每次聽到新的 Pod 時,它都會決定應該在哪個節點上執行。 Scheduler 並沒有執行 Pod,只是告訴 API** 它為其選擇了哪個節點。然後 API 將保存該資訊。 另一個監聽 Pod 事件的元件是 Kubelet,它是執行在 Kubernetes 叢集中每個工作節點上的元件。每次 API 告訴 Kubelet Scheduler 決定在其節點上執行 Pod 時,Kubelet **將啟動 Pod 定義的所有容器**。 最後,我們將配置變成了在機器上執行的應用程式!這是一個漫長的過程,有很多移動部分,但這可能是我最喜歡的部分。 每個元件只承擔部署應用程式的一小部分責任,但它們一起解決了一個相當複雜的問題。 ## 最後的想法 希望本文能幫助您掌握 Kubernetes 元件,並幫助您揭開最受歡迎的編排器的神秘面紗。我們鼓勵您自行挖掘,因為我們很高興了解這一點。 我們推薦學習 Kubernetes 的一本書是 Marko Lukša 的《Kubernetes in action》。它非常受歡迎,並且很好地概述了 Kubernetes 背後發生的事情以及如何使用它。 --- 原文出處:https://dev.to/cyclops-ui/complexity-by-simplicity-a-deep-dive-into-kubernetes-components-4l59

初級開發人員需要掌握的 12 個資深開發人員特質 🔥

在任何領域,無論是藝術、體育還是軟體開發,達到頂峰的最快方法就是研究那些已經處於頂峰的人……並做他們正在做而你沒有做的事情。 如果您以編寫程式碼為生,這意味著要考慮一下高級開發人員。這意味著確定他們擁有哪些你不具備的技能、習慣和特質。 在過去 3 年裡與全球頂尖軟體工程師一起工作了數千個小時之後,我發現您現在就可以實施 12 種高級開發人員特質,以快速將您的成長提升到一個新的水平。 讓我們從第一開始… ## 1. 專注 專注意味著對某些事情說不,這樣我們就可以做其他事情。 理想情況下,對不重要的事情說不。並對那些能帶來改變的事情說「是」。使船移動得更快的東西。 這對許多開發人員來說確實很難,因為它違背了我們的本能。這意味著接受你無法完成所有事情。並不是每個機會都是平等的。 你不可能學習所有新的框架。您無法閱讀所有時事通訊。您不可能參加所有會議。而你不必這樣做。 你的時間有限。你的能量也是如此。 成為高級開發人員意味著選擇你的戰鬥。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wftnt9w68gjflh2yghs0.png) > 「人們認為專注意味著對你必須關注的事情說『是』。但這根本不是這個意思。這意味著對其他一百個好主意說不。” ——史蒂夫‧賈伯斯 有趣的是,你選擇的越好,你進步的速度就越快。高級開發人員每天都有 24 小時的時間。但他們做得更多。 如何? 透過少做事。 當新事物出現時,問問自己“這真的很重要嗎?”或者這只是另一個趨勢?很可能這只是另一個偽裝成機會的干擾。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pgqenoavc69esm48yf06.png) 高級開發人員說的「不」多於「是」。他們完成的專案比開始的專案還要多。他們在學習新框架之前先掌握已經使用的框架。如果你想更快進入高級,你需要培養的第一個特質就是專注。 ## 2. 二階思維 讓「初級開發者」尖叫的一件事是「讓我們建造它,我們會找到結果」的態度。年輕人傾向於先編碼,後思考。 如果您剛開始,這可能是一個很好的態度,但是當您開發可用於生產的軟體時,您將無法更改一些技術決策。或者很容易改變。 例如,您選擇Vue作為前端框架。 然後,需求會改變。你開始認為 React 會是更好的選擇。當然,你可以切換到 React。但這既不容易,也不便宜。 資深開發人員知道,靠自己的供應很容易獲得快感。但是,如果您愛上了您最了解的框架和函式庫,您將開始做出糟糕的技術決策。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9eb6xwgv7jhmn4p7qcq1.png) 他們會三思而後行,考慮自己選擇的後果。這可能意味著在嘗試理解問題時詢問「五個為什麼」。 或考慮他們的解決方案可能存在的缺點。 例如,現在我們新增了 Redux,全域狀態可能更容易管理。但我們必須在 Redux 上招募新的開發人員。學習曲線很高。 而且,你猜怎麼著,我們的 JavaScript 套件會變得更大,這對效能不利。 考慮二階環境將使您成為更好的開發人員。它還將在技術面試中為您提供幫助。 🚨 PS您是否希望快速晉升為擁有優質資源、回饋和責任的高階開發人員? [點擊此處加入我們的免費社區 - 高級開發學院。](https://bit.ly/3GJuOjr) 🚨 ## 3.實用主義 當初級開發人員閱讀一本關於最佳實踐的書時,他們會跳起來並嘗試將它們應用到任何版本中的每一行程式碼。他們虔誠地追隨他們。 如果您無法自己做出技術決策,那麼遵守預先定義的規則會容易得多。但軟體開發不是一種宗教。 一個很好的例子是測試。 當初級開發人員閱讀 TDD(測試驅動開發)時,他們將開始嘗試測試所有內容。旨在實現完整的程式碼覆蓋率。事實上,完整的程式碼覆蓋率會帶來遞減的結果,並且最終會浪費時間。 ![每個發現 TDD 的初級開發人員](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/do0uxbjna2alz58b3mvg.png) 高級開發人員知道如何平衡最佳實踐和上市時間。何時走捷徑,何時不走捷徑。 快速破解會產生錯誤和技術債。當程式碼上下文發生變化時,始終遵守規則會導致錯誤的決策。 你需要一個平衡。 根據情況重新考慮您的技術選擇。 ## 4. 沒有什麼好證明的 由於缺乏自信,初級開發人員發現自己不斷地試圖向他人證明自己。與對自己的價值和技能缺乏安全感的高級開發人員一樣。 他們的信心是建立在他人的認可之上。 這是一場失敗的遊戲。 他們會嘗試在某個技術討論、與他人交談或在深夜或週末推送程式碼時展示自己了解多少。 事實上,所有這些行為都會造成有毒的團隊環境並適得其反。在最好的情況下,他們會讓你看起來比實際情況更高級。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1sfp7p24zru1r9zafd05.png) 獵豹不需要在比賽中證明自己,它只是為了狩獵而奔跑。 有兩種方法可以解決這個問題。 第一個是停止在外部驗證上花費太多。因為事實是你不需要向任何人證明自己。只對你自己。 第二是與頭腦中的負面聲音和平相處。 你可以成為你最嚴厲的批評者。完美主義、對失敗的恐懼以及對「真正的」開發人員的錯誤認知正在摧毀你的自尊。這就是為什麼無論你多努力,你總是感覺功虧一簣。 是時候擺脫你的頭腦了。 專注於掌握你的手藝,剩下的就會水到渠成。您將立即對自己和自己的技能更加自信。你將不再試圖向陌生人證明自己。 ## 5. 掌握基礎知識 每當我在 LinkedIn 上看到開發人員的個人資料,並且他們將自己描述為「React」開發人員或「Angular」開發人員時,我就知道他們不是高級開發人員。他們可能是該框架中的高級人員,但總體而言不是高級人員。 框架開發人員永遠不會成為高級開發人員。 框架不會讓你成為高級,因為框架只是錦上添花。不是蛋糕本身。冰山一角與其底部。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/chomoxfdvoemx4m4n15o.png) 我甚至推測,目前軟體開發人員中冒充者症候群盛行的背後,甚至是高階開發人員的背後,並不是缺乏天賦,也不是缺乏努力。 這是基本面薄弱。 這也是為什麼除錯或效能優化等主題對於大多數開發人員來說是一個猜謎遊戲。他們不習慣深入挖掘他們正在使用的庫和工具的表面。 要成為高級開發人員,您不僅必須了解事物背後的“什麼”,還必須了解事物背後的“原因”。 例如,高級開發人員不僅能夠建立 React 應用程式。但他們也會理解為什麼 React 是以某種方式建構的。以及它如何與編寫的語言(JavaScript/TypeScript)和執行的平台(Web 瀏覽器)融合。 好訊息是,一旦你掌握了基本原理,一切的水平都會上升。 🚨 PS您是否希望快速晉升為擁有優質資源、回饋和責任的高階開發人員? [點擊此處加入我們的免費社區 - 高級開發學院。](https://bit.ly/3GJuOjr) 🚨 ## 6. 端對端交付 公司避開初級開發人員的第一大原因是他們需要大量外部協助才能完成工作。外部幫助意味著您將打擾高級開發人員來完成您的工作。 初級開發人員被認為“昂貴”,因為他們無法獨立交付。 相反,高級開發人員可以提供端到端的服務。給他們一堆要求,他們會解決剩下的問題。這並不意味著他們是獨狼,而且他們通常非常擅長團隊合作。 這並不意味著高級開發人員快速破解事物只是為了推動它們前進。 那不是「真正的」前輩。 這並不意味著他們深入了解軟體開發生命週期的每個部分。 但是,高級開發人員了解整個軟體開發生命週期的所有主要部分。並且可以為其中的每一個(前端、後端、部署)做出貢獻。 如果您是想要升級的初級/中級開發人員,那麼端對端交付是您需要關注的特徵。 ## 7. 心智模型 高級開發人員與初級開發人員的主要區別之一是他們可以處理的複雜性。 老年人可以理解更複雜的程式碼庫和需求。 他們可以理解二階環境。程式碼庫的變化將如何影響效能、成本甚至團隊。 他們這樣做並不是因為他們記住了每個實作細節。這是不可能的,因為人類的記憶非常有限。 他們這樣做是因為他們將程式碼的複雜度抽象化為心理模型。這些都是表示現實的簡單方法。 開發人員如何建構高品質的心理模型? 透過查看框架和庫的背後並學習它們背後的設計模式。根據您的技術堆棧,存在著許多噪音。諸如 SOLID 原則或 MVC 之類的東西... 但我認為最好的開始方法是選擇您正在使用的任何框架並嘗試超越程式碼。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hk2opgm1njc76p0a6k0n.png) 開始問自己,為什麼框架的建立者要這樣建構它?它是建立在新概念的基礎上還是只是古老原則的實現(通常是這種情況)? 透過回答這些問題,您將建立軟體開發的思維模型,並能夠處理更多的複雜性。這是快速成長為高級開發人員的最有效方法之一。 🚨 PS您是否希望快速晉升為擁有優質資源、回饋和責任的高階開發人員? [點擊此處加入我們的免費社區 - 高級開發學院。](https://bit.ly/3GJuOjr) 🚨 ## 8. 資深開發人員控制故事 高階開發人員可以做得非常好的一件事是領導技術討論並影響周圍的其他人。無論是業務利害關係人、產品經理或其他開發人員,資深開發人員都知道如何引導他們朝著正確的方向發展。 他們結合自信、技術專長和溝通技巧來做到這一點。 高級開發人員也能夠設定嚴格的界限。 他們可以不同意而不會情緒激動。他們可以在會議期間為自己(和他人)挺身而出。他們積極協商薪資。 他們講述自己的故事。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pd8vutmtz3wbxas13ey1.png) 高級開發人員知道如何以及何時在沙子上劃線並說“夠了”。 如果另一個開發人員在程式碼審查期間開始指責其他人,老年人知道如何阻止他們。如果高階主管試圖介入開發人員的工作並進行微觀管理,高階管理層知道如何在不破壞關係的情況下阻止他們。 沒有關於如何變得更加自信的開發人員的分步指南。 這需要重複和練習。第一步是停止一直說「是」。並開始嘗試在薪資談判中取得進展。 ## 9. 長期思考 初級開發人員考慮“現在”。他們的想法是短期的。當他們走捷徑時,他們的程式碼也是如此。初級開發人員會擴展一段程式碼,而不考慮正確重構它,或乾脆忽略測試和效能。 但青年人也會對自己的職業生涯進行短期思考。 這可能意味著跳槽過多或自毀前程。這可能意味著忽視。 就像不提高你的技能或推銷自己的方式一樣,因為現在你的工作很穩定。只是被解僱六個月後才後悔。 成為更高級的開發人員的一部分是開始進行長期思考。 第一個方法是改變你的心態。大多數初級開發人員的短期思維不是由懶惰引起的,而是由自我懷疑引起的。 他們內心深處仍在思考成為開發人員是否適合他們。或者他們是否選擇了正確的職業。 這些疑慮阻止他們做出長期承諾。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sw1r4ng1hoyigg3e0z6v.png) 好事需要時間,資深開發人員知道這一點並相應地調整他們的想法。 現在,隨著人工智慧威脅到軟體開發的終結,這種短期思維比以往任何時候都更加頻繁。如果某件事很快就會消失,為什麼還要承諾呢? 相信我,只有當我完全致力於我作為開發人員的職業生涯時,事情才開始起飛。 我說:「就是這樣」。 我不再向外張望。我告訴自己:這是我現在的工作,也是我未來十年的工作,所以讓我把它做好吧。 我開始投資我的技能,因為現在我知道它們會得到回報。 即使你未來 20 年不打算寫程式碼,擁有長遠的心態也會為你帶來巨大的好處。高級開發人員之所以能夠達到高級水平,是因為他們致力於自己的技術。如果您渴望實現這一目標,您也應該這樣做。 🚨 PS您是否希望快速晉升為擁有優質資源、回饋和責任的高階開發人員? [點擊此處加入我們的免費社區 - 高級開發學院。](https://bit.ly/3GJuOjr) 🚨 ## 10.卓越是一種習慣 我想正是 Kent Beck 說過那句名言:「我不是一個偉大的程式設計師,只是一個有著好習慣的好程式設計師」。習慣很重要,因為它們經得起時間的考驗。 因為您擁有的任何關於 JavaScript 框架的知識遲早都會過時。技術變革。但你的習慣將永遠伴隨你。 好訊息是人類是習慣的動物。 在我們的大腦中設定新的慣例並不容易。 但一旦我們將它們內化為習慣,我們就很容易堅持下去。利用這一點的最佳方法是實現您的任何目標並將其分解為日常行動。然後透過重複將這些行為變成習慣。 例如,如果您想更好地進行測試,請每天編寫一個單元測試。 如果您想在日常會議中做好更多準備並清晰思考,請寫日記。如果你想找到一份新的開發人員工作,並且你必須發送 100 份申請,那麼每天發送 10 份申請。 養成新的習慣,你向高級水準的進步將持續且穩定。 ## 11. 保護您最重要的資產 身為高階開發人員意味著不僅要長遠考慮您的程式碼和技術決策,還要考慮您的健康。 因為健康就是財富。 我在影片中一次又一次地談論這一點。 開發人員的工作需要久坐。您一天的大部分時間都坐在電腦前的椅子上。這對你的健康非常不利。 然後,辦公室裡到處都是垃圾食品,像是薯條、汽水和糖果。這意味著除非您有意識地努力,否則您將很難保持健康和體形。 但如果你想擁有一個長期而富有成效的軟體編寫職業,並且不想最終出現背部問題、糖尿病,甚至更糟糕的情況,那麼你需要開始照顧自己的健康。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fsdohne0ydvireyloigf.png) 欲得金蛋,勿殺鵝。如果你想提高工作效率,首先要照顧好自己。 這並不意味著您必須開始每週去健身房 5 次。 或進行一些瘋狂的節食。但每周至少2至3次運動。您可以去健身房、跑步或參加團隊運動。現在我正在做 在飲食方面,減少糖和精緻碳水化合物的攝取。肉也不要過量。 也要考慮您的心理健康。 忽略諸如「吃飯、睡覺、編碼、重複」之類的建議,在工作之外建立自己的生活。 開始一個新的嗜好。聯繫朋友。休息一下。 從短期來看,你的進步可能會慢一些。但從長遠來看,你將能夠在遊戲中停留更長時間。 🚨 PS您是否希望快速晉升為擁有優質資源、回饋和責任的高階開發人員? [點擊此處加入我們的免費社區 - 高級開發學院。](https://bit.ly/3GJuOjr) 🚨 ## 12. 閉合圓圈 最後,資深開發人員了解業力是如何運作的。他們知道,無論他們多麼努力,或者多麼聰明,在他們走向頂峰的道路上,都有數十個人的幫助。 這並沒有剝奪他們的優點,但也承認其他人。 所以他們關閉了這個圈子。 他們幫助其他開發人員。他們這樣做是沒有期望的。 不是因為它可能會讓你升職。或是地位,或是仰慕。他們這樣做是因為這是正確的事。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/urp75psyn2lz8oah3cq7.png) 甚至科比·布萊恩也抽出時間來指導年幼的孩子並讓他們進入籃球領域。您也可以抽出時間來幫助新開發人員。 幫助剛起步的人會帶給你部分火花。初學者第一次看到事物時所感受到的熱情和好奇心是如此具有感染力。 另一件你可以變成日常習慣的事情! 好的,就是這樣。具備這 12 個特徵,您將快速成長到高級甚至更高級別。 --- 原文出處:https://dev.to/dragosnedelcu/12-senior-developer-traits-junior-developers-need-to-master-285m

為什麼我不推薦 Robert C Martin 的《Clean Architecture》

*乾淨的架構*在許多方面都未能滿足我的期望。儘管 Martin 先生對這個主題表現出明顯的熱情,但「清潔架構」組織得很差,缺乏範例,並且對使用現有系統保持沉默。作者錯過了一個重要的機會來教導我們何時以及如何將這些經驗教訓應用到我們自己的系統中。讓我解釋。 ### *乾淨的架構*是一本組織得很差的書 這本書需要很長時間才能開始。關於設計範式(結構化、物件導向和函數式)的章節似乎特別不合時宜且不必要。 關於 SOLID 原則的章節很好。我很高興看到這些原則被分解並得到很好的解釋。我發現思考它們對系統架構的適用性很有趣。但鮑伯叔叔提出了諸如硬性規則之類的堅實原則,這讓我感到不舒服。事實上,我非常確定一個***從未***違反 SOLID 原則的系統將是一個巨大的混亂。 然而,第 137 頁的這一段很重要: >架構的主要目的是支援系統的生命週期。良好的架構使得系統易於理解、易於開發、易於維護、易於部署。最終目標是最小化系統的生命週期成本並最大化程式設計師的生產力。 這是一個很好的觀察。叔叔鮑伯為什麼不把它放在第一章呢? ### 例子不夠多 本書中幾乎沒有任何例子。第 33 章包含一個討論影片銷售電子商務應用程式的範例。沒關係。但我並沒有明確地知道如何將這些概念應用到我自己的系統中。 附錄講述了 Bob 叔叔如何提出 SOLID 原則和乾淨架構規則的故事。它載有過去專案的範例。我認為這是本書**最有趣的部分**。 ### 這本書沒有提到改進現有系統的架構 大多數開發人員將大部分時間花在現有系統上。因此,我期望 *[Clean Architecture](https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164/)* 充滿有關改進現有系統的建議。但這本書在這個問題上顯然隻字不提。 ### 如何建立一個乾淨的架構? 在本書的前半部分中,您將了解如何透過遵循 SOLID 原則將系統沿系統邊界分解為元件來建立一個乾淨的架構(我是這樣解釋的)。如果你停止閱讀那裡,你可能會有這樣的印象:叔叔鮑伯不會批准你為建築所做的一切,這是可以理解的。如果你認為他提出的幾個選項是「正確」的做事方式,這也是情有可原的。然而,在本書的最後,您將在第 228 頁讀到: >這個例子旨在顯示架構邊界無所不在。作為建築師,我們必須小心地辨識何時需要它們。我們也必須意識到,如果完全實施這些邊界,其成本是昂貴的。 >同時,我們必須認識到,當這些邊界被忽略時,即使存在全面的測試套件和重構規則,以後加入它們的成本也會非常昂貴。 >那我們建築師該怎麼辦?答案令人不滿意。一方面,多年來,一些非常聰明的人告訴我們,我們不應該預見抽象的需要。這就是 YAGNI 的哲學:“你不會需要它。”這句話充滿智慧,因為過度設計往往比設計不足更糟。另一方面,當您發現確實需要一個不存在的架構邊界時,加入這樣一個邊界的成本和風險可能會非常高。 >所以你已經得到它了。軟體架構師啊,你必須看見未來。你必須聰明地猜測。您必須權衡成本並確定架構邊界在哪裡,哪些應該完全實現,哪些應該部分實現,哪些應該被忽略。 因此,在本書的一半以上,他說應該由我們來決定我們的系統的邊界在哪裡。這種界限可能無所不在。令人困惑,對吧? ### 這本書缺少什麼 因此,如果軟體架構的最終目標是最小化系統的生命週期成本,那麼一本關於架構的書不應該幫助架構師做出這些決策嗎? #### 未解答的問題 這本書給我留下了很多未解答的問題。各種選擇的經濟學討論在哪裡?如何找到最適合我的系統的架構?研究在哪裡? ![未解答的問題](https://thepracticaldev.s3.amazonaws.com/i/fll25irsu1xbd0268kq2.jpg) 我該如何決定水平分層、垂直切片或其他方式是否可以最大限度地降低系統的生命週期成本?或者,如果我沒有明確定義的層,我該如何決定哪種分層策略(如果有)可以最大限度地降低我的生命週期成本? 我還有更多問題。如果您改進現有系統架構的時間有限,您應該把精力放在哪裡?將資料庫與業務邏輯分開總是一個好主意嗎?您應該始終遵循哪些建議?哪些建議取決於系統? #### 讓*乾淨的架構*更有價值的細節 在*[Code Complete](https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/)*中,Steve McConnell 討論了不同非功能性需求(例如可靠性、可靠性)之間的權衡、正確性、可維護性、可讀性等。他解釋了一些需求如何協調一致而另一些需求如何衝突。我很樂意看到類似的東西用於本書中討論的架構決策。 在*清潔架構*中,專案規模、團隊規模、專案失敗的後果、預期程式碼生命週期和其他重要因素作為架構的驅動因素沒有得到足夠的重視。例如,Healthcare.gov 需要比您正在開發的個人待辦事項清單更多的架構,即使它們都是由資料庫支援的 Web 應用程式。 ### 這本書的真正內容是什麼 本書的大部分內容我都感到有些困惑。我有點明白叔叔鮑伯想說什麼。但直到讀了附錄才完全明白。那麼,讓我為您節省一些時間。 #### 一個例子 想像一下您正在為消費市場建立一台桌上型電腦(例如辦公室電腦)。您可以選擇硬件,然後為整個系統編寫軟體(韌體、作業系統、驅動程式、應用程式等)。 #### 你會寫一個整體嗎? 你會怎樣做呢?您會編寫一個巨大的程式(一個整體),其中電子表格的程式碼知道您為電腦選擇的磁碟類型嗎?您能否想像更新電子表格程式碼並在各處新增「if」語句,以便在您有 SATA 磁碟機時執行一件事,而在有 SCSI 磁碟機時執行另一件事?然後對 VGA、DVI 和 HDMI 視訊做同樣的事情? PS/2 與 USB 滑鼠輸入的不同路徑怎麼樣?然後對文字處理器和您打算與電腦捆綁的所有其他應用程式重複該過程? 維護這將是一場惡夢,對嗎?那麼解決方法是什麼呢?建築學!您的電子表格不應該知道您使用的是哪種滑鼠。也不知道你有什麼樣的顯示器。它應該完全忘記這些細節。 #### 計算機中的邊界 如果您查看計算機,您會發現這一點。您的滑鼠中有嵌入式軟體,可以與作業系統進行通訊。然而,詳細資訊對您的應用程式是隱藏的。您的電子表格接受標準化輸入,而無需知道或關心您使用的滑鼠類型。然後,當有人發明了新的輸入裝置(例如觸控板)時,它會自動與您的電子表格配合使用。 這只是計算機的邊界之一。您可能會想出數百個。您可以指派不同的團隊來處理系統的不同部分。您可以為不同元件互動的各種方式建立或採用不同的規格。 此時你可能會說「呃」。顯然,您不希望每次硬體發生變化時都更改並重新編譯電子表格。維護將是一場惡夢。並且我同意。 #### 邊界是你的朋友(如果你正確使用它們) 很容易看出硬體邊界。但使硬體邊界變得有價值的相同邏輯也適用於軟體邊界。軟體邊界更難看到。 因此,您可以從在螢幕上顯示電子表格的能力開始。但您可能還想將其儲存到磁碟、儲存為 PDF、儲存為 CSV 或列印。因此,電子表格程式的邊界之一可能是擁有代表每個電子表格的內部資料結構。然後將該結構傳遞給不同的程式碼,以所需的格式顯示、儲存或列印它。 如果您讓資料結構完全不知道它是如何顯示、保存或列印的,那麼您可以在以後加入「儲存到 XML」功能,而無需深入研究與電子表格資料結構相關的所有程式碼。如果電子表格資料結構有幾百萬行程式碼,您可以想像這會容易得多。 這就是鮑伯叔叔在本書中試圖告訴我們的全部。 **您可以使用 SOLID 原則在系統中建立邊界,隱藏實作細節、降低複雜度並幫助您降低系統的總生命週期成本**。 ### 一本更好的軟體架構書 在許多方面,Martin Fowler 的*[企業應用程式架構模式](https://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420/)* 遠遠優於*清潔架構* 。 Fowler 描述了他在企業應用程式中反覆觀察到的模式。他給出了每個模式的簡單範例,描述了它的工作原理以及在何處使用它。我發現“企業應用程式架構模式”非常可讀並且適用於我的系統。 ### 要點 *乾淨的架構*中有有價值的訊息,但你必須努力找到它。 我發現有關嵌入式軟體的章節是最容易理解的章節之一。直觀上,避免在整個程式碼庫中分散低階呼叫是有意義的。在沒有硬體的情況下使邏輯可測試也是有意義的(特別是因為嵌入式軟體通常是在硬體可用之前開發的)。如果您只能閱讀本書的兩章,我建議您閱讀這一章和附錄,無論您以編寫哪種軟體為生。 總的來說,《乾淨的架構》是一本很難讀的書,鮑伯叔叔留給我的問題比答案還多。我絕對不會推薦這本書作為您關於軟體架構的第一本書(請查看*[企業應用程式架構模式](https://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420/ )* 由馬丁·福勒取代)。 *同意還是不同意。我很想聽聽你的想法。* *喜歡這篇文章嗎?請在下面“喜歡”它。* --- 原文出處:https://dev.to/bosepchuk/why-i-cant-recommend-clean-architecture-by-robert-c-martin-ofd

Supabase Auth:身分連結、Hooks 和 HaveIBeenPwned 集成

我們很高興地宣布 Supabase Auth 的四項新功能: 1. 身份連結 2. 會話控制 3. 密碼外洩保護 4. 帶有 Postgres 函數的 Auth Hooks {% 嵌入 https://youtu.be/LF8GABnAFyE %} ## 身份連結 當使用者登入時,系統會使用身份驗證方法和登入提供者建立身分。從歷史上看,如果身分與使用者共享相同的經過驗證的電子郵件,[Supabase Auth](https://supabase.com/docs/guides/auth) 會自動將身分連結到使用者。這可以方便地刪除重複的用戶帳戶。然而,一些開發人員還需要靈活地連結不共享相同電子郵件的帳戶。 今天,我們推出身份連結,開發人員可以使用它手動連結兩個單獨的身份。我們為開發人員新增了兩個新端點來管理身分連結流程: 使用者登入後,使用「linkIdentity()」[連結 OAuth 身分:](https://supabase.com/docs/reference/javascript/auth-linkidentity) ``` const { data, error } = await supabase.auth.linkIdentity({ provider: 'google', }) ``` 使用 `unlinkIdentity()` 來[取消連結身分](https://supabase.com/docs/reference/javascript/auth-unlinkidentity): ``` // retrieve all identities linked to a user const { data: { identities }, } = await supabase.auth.getUserIdentities() // find the google identity linked to the user const googleIdentity = identities.find(({ provider }) => provider === 'google') // unlink the google identity from the user const { data, error } = await supabase.auth.unlinkIdentity(googleIdentity) ``` 目前,這些方法支援連結 OAuth 身分。要將電子郵件或電話身分連結到用戶,您可以使用 [updateUser()](https://supabase.com/blog/supabase-auth-identity-linking-hooks#:~:text=can%20use% 20the -,updateUser(),-method.)方法。 預設情況下禁用手動連結。您可以在[儀表板驗證設定](https://supabase.com/dashboard/project/_/settings/auth) 中為您的專案啟用它。 ![如何啟用手動連結](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kmsrmiw0ue3q5rshji7v.jpg) > 有關更多訊息,請參閱[身份連結文件](https://supabase.com/docs/guides/auth/auth-identity-linking)。 ## 會話控制 Supabase Auth 從使用者登入應用程式那一刻起管理整個會話生命週期。這涉及以下步驟: 1. 為使用者建立會話。 2. 刷新會話以使其保持活動狀態。 3. 過期或登出時撤銷會話。 對於想要更好地控制使用者會話的開發人員,我們公開了 3 個新設定: - **時間盒使用者會話:** 強制使用者在一段時間間隔後再次登入。 - **不活動逾時:** 如果使用者在一段時間內不活動,則強制使用者重新登入。 - **每個使用者單一會話:** 將使用者限制為單一會話。保留最近的活動會話,並終止所有其他會話。 這些會話控制設定在專業版及以上版本中可用。 ![如何強制每個使用者單一會話](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aov0nw5xch0m4hw97vsg.jpg) > 有關更多訊息,請參閱[會話管理文件](https://supabase.com/docs/guides/auth/sessions)。 ## 密碼外洩保護 由於常見的使用者行為(例如選擇可猜測的密碼或在不同平台上重複使用密碼),密碼本質上可能是不安全的。 儘管 OAuth 和 magiclinks 更安全,但我們認識到密碼將繼續存在。我們希望讓用戶不易陷入潛在的陷阱。為了實現這一目標,我們在 Supabase Auth 中整合了 [HaveIBeenPwned.org](https://haveibeenpwned.com/) _Pwned Passwords API_,以防止使用者使用洩漏的密碼。 > **去圖書館** ℹ️ 我們開源了一個 Go 函式庫,用於與我們在身分驗證伺服器中使用的 [HaveIBeenPwned.org](http://haveibeenpwned.org/) Pwned 密碼 API 互動。查看 [存儲庫](https://github.com/supabase/hibp) 並隨時貢獻! 作為附加步驟,我們新增了為您的使用者指定密碼要求的功能。這可以透過[儀表板:](https://supabase.com/dashboard/project/_/settings/auth) 中專案的身份驗證設定進行配置 ![新增密碼要求](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3o9ax3tudp7v8tba67hd.jpg) > 請參閱[密碼文件](https://supabase.com/docs/guides/auth/passwords) 以了解更多資訊。 ## 驗證掛鉤 我們收到了大量回饋,詢問如何自訂 Auth,例如: - 將自訂聲明新增至存取權杖 JWT - 多次嘗試 MFA 驗證失敗後註銷用戶 - 對密碼驗證嘗試套用自訂規則 我們的目標是保持簡單、無縫的 Supabase Auth 體驗。對於大多數開發人員來說,它應該可以輕鬆工作,而無需自訂。但是,認識到應用程式的多樣性,您現在可以透過 Auth Hook 擴展標準 Auth 功能。 Auth Hooks 只是 Postgres 函數,它們在 Auth 生命週期的關鍵點同步執行,以更改操作的結果。 例如,要使用 Auth Hooks 自訂 JWT 聲明,您可以建立一個 Postgres 函數,該函數接受第一個參數中的 JWT 聲明並傳回您希望 Supabase Auth 使用的 JWT。 假設您正在建立一個遊戲化應用程式,並且希望將用戶的層級作為自訂聲明附加到 JWT: ``` create function custom_access_token_hook(event jsonb) returns jsonb language plpgsql as $$ declare user_level jsonb; begin -- fetch the current user's level select to_jsonb(level) into user_level from profiles where user_id = event->>'user_id'::uuid; -- change the event.claims.level return jsonb_set( event, '{claims,level}', user_level); end; $$ ``` 在資料庫中建立函數後,您只需使用 Supabase Auth 註冊它: ![Auth Hooks](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/unkgs56o62l8c4kfjzjg.jpg) 目前,您可以為流程中的以下點註冊 Auth Hook: - **自訂存取權杖:** 每次產生新的 JWT 時都會呼叫。 - **MFA 驗證嘗試:** 每次驗證 MFA 因素時都會呼叫,從而可以更好地控制檢測和阻止嘗試。 - **密碼驗證嘗試:** 每次使用密碼登入使用者時都會呼叫,從而可以更好地控制使用者帳戶的安全性。 如果編寫 PL/pgSQL 函數不是您的強項,您始終可以使用 [pg_net](https://supabase.com/docs/guides/database/extensions/pg_net) 向後端 API 發送請求,或使用[plv8]( https://supabase.com/docs/guides/database/extensions/plv8) 透過用JavaScript 編寫函數來更輕鬆地操作JSON。 Auth Hooks 今天可供自架,並將於下個月推出到該平台。如果您需要盡快存取,請透過[支援](https://supabase.help/)與我們聯繫! 那不是全部! Postgres 函數並不是寫鉤子的唯一方法。 Supabase 是 [Standard Webhooks](https://www.standardwebhooks.com/) 的創始貢獻者,這是一組關於輕鬆、安全、可靠地發送和接收 Webhook 的開源工具和指南。當然,Auth Hooks 將在 2024 年第一季支援 Webhooks。 ## 還有一件事… 如果您從一開始就關注我們(https://supabase.com/blog/supabase-auth),您就會知道Supabase Auth 是透過分叉[Netlify 的GoTrue 伺服器](https://github.com)開始的/netlify/gotrue)。從那時起,發生了很多變化,我們已經偏離了上游儲存庫。在這個階段,將專案重新命名為其他名稱是有意義的(提示鼓聲)-Auth。 這僅僅意味著儲存庫將從使用“gotrue”重新命名為“auth”。但別擔心! Docker 映像和庫(如“@supabase/gotrue-js”)將繼續發布,只要當前 v2 版本受支持,您就可以互換使用“@supabase/auth-js”。所有類別和方法都保持不變。這裡沒有重大變化! ## 結論 感謝您閱讀到最後!我們希望您喜歡第 X 週發布的 Supabase Auth 更新:身分連結、會話控制、洩露密碼保護和帶有 Postgres 功能的 Auth Hooks。 我們期待看到您使用這些新功能建立的內容,當然還有您的回饋意見,以使它們變得更好。 ## 更多發布第 X 週 - [第 1 天 - Supabase Studio 更新:AI 助理與使用者模擬](https://supabase.com/blog/studio-introducing-assistant) - [第 2 天 - Edge Functions:節點和本機 npm 相容性 ](https://supabase.com/blog/edge-functions-node-npm) -[第 3 天 - 介紹 Supabase Branching,這是一個針對每個拉取請求的 Postgres 資料庫](https://supabase.com/blog/supabase-branching) - [Postgres語言伺服器:實作解析器](https://supabase.com/blog/postgres-language-server-implementing-parser) - [Supabase 專輯](https://www.youtube.com/watch?v=r1POD-IdG-I) - [Supabase 啟動週 X 黑客松](https://supabase.com/blog/supabase-hackathon-lwx) - [啟動週 X 社群聚會](https://supabase.com/blog/community-meetups-lwx) --- 原文出處:https://dev.to/supabase/supabase-auth-identity-linking-hooks-and-haveibeenpwned-integration-19e1

用 React 和 Node.js 建立 GPT Web 應用程式產生器 - 在 4 個月內,從點子到 25,000 個應用程式

我們正在開發 [Wasp](https://github.com/wasp-lang/wasp) - 一個基於 React、Node.js 和 Prisma 建置的全端 Web 框架。自從 GPT 出現以來,我們想知道是否可以使用它來更快地建立 Web 應用程式。這讓我們想到了 [MAGE - 一個由 GPT 驅動的 Web 應用程式產生器](https://usemage.ai/),它可以根據簡短的描述建立完整的堆疊程式碼庫。 我們已經寫過[MAGE 可以(和不能)做什麼](https://dev.to/wasp/gpt-web-app-generator-let-ai-create-a-full-stack-react-nodejs-codebase-based-on-your-description-2g39)和[它在幕後的工作原理](https://wasp-lang.dev/blog/2023/07/17/how-we-built-gpt-web-app-generator)。這是關於它的起源和採用的故事 - 為什麼我們決定建立它,開發人員如何發現它,以及他們實際上用它做什麼。 ## 為什麼要建構另一個 AI 編碼代理? 我們很晚才進入整個 GPT 編碼代理遊戲。在我們開始考慮建立自己的工具之前,Smol AI、GPT Engineer 和 MetaGPT 等工具就已經受到了廣泛的關注,我們對此也很清楚。 ![編碼代理景觀](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zw6vyjt79bxrsyvdhl78.png) 那為什麼還要麻煩呢?事實是,這些代理程式都不是專門為建立 Web 應用程式而設計的,而這正是我們看到機會的地方。 儘管使用 GPT 代理進行編碼可以讓人感覺超級強大,但它們通常會很慢並且沒有抓住要點,需要多次迭代,最終使該過程相當麻煩且昂貴。 有了這些經驗,我們想知道,*「如果我們為特定堆疊中的 Web 應用程式製作一個高度專業化的編碼代理,而不做其他事情會怎麼樣?它能變得更容易、更快、更便宜嗎?」* 儘管我們對此很感興趣,但作為一個兼顧多個優先事項的小團隊,我們仍然相當懷疑,幾乎放棄了整個專案。事實證明,它的效果比我們預期的還要好。 ## 第 1 步:建造它🛠️ ![運作方式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lkqk1i0p311u9zd9ouk6.png) 在決定 MAGE(*Magic App Generator*)的 v0 版本時,我們考慮了多種選擇。第一個也是最直接的一個是將其與 Wasp CLI 集成,因為我們已經擁有了圍繞它的所有工具。然後,開發人員將執行“wasp new myProject -ai”,而不是執行“wasp new myProject -ai”,CLI 會要求他們提供應用程式描述和其他所需的輸入,然後在終端中完成所有工作。 另一方面,我們知道在開始描述您的應用程式之前下載並安裝 Wasp 是一個很大的要求。最重要的是,CLI 中的使用者介面功能非常有限。這就是我們選擇網路介面的原因 - 零摩擦開始,我們可以讓應用程式建立流程變得非常簡單且美觀。 花了幾週的時間來建構它,最終的結果是一個[用Wasp 製作的完全開源的Web 應用程式](https://github.com/wasp-lang/wasp/tree/wasp-ai/wasp-ai)可以在 https://usemage.ai/ 上免費使用,或在本地託管以獲得更多控制和靈活性(例如,使用您自己的 OpenAI API 金鑰)。 ### 超級具體(僅限網頁應用程式)得到了回報! ![法師計畫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xqkrqj8b3we67ufxl8gm.png) 如上所述,我們的主要賭注是建立一個專門的編碼代理來建立全端 Web 應用程式,而不是其他任何東西,這得到了回報。它使我們能夠預先為代理提供大量上下文和結構,並引入專門的啟發式方法來修復錯誤。此外,由於 Wasp 的高級抽象(例如身份驗證、專案結構、查詢和作業系統等),我們顯著減少了錯誤的表面積。 另一個結果是執行時間顯著減少,甚至更重要的是成本減少。典型的MAGE 建立的Web 應用程式成本在0.10 至0.20 美元之間,而一般編碼代理[同一應用程式的花費可能高達10 美元](https://wasp-lang.dev/blog/2023/08/01/smol-ai-vs-wasp-ai#thoughts--further-considerations)(所有價格均在 OpenAI 23 年 11 月 7 日定價更新公告之前)。 您可以閱讀有關Wasp 內部工作原理的更多資訊[此處](https://wasp-lang.dev/blog/2023/07/17/how-we-built-gpt-web-app-generator),以及它的比較其他編碼代理[此處](https://wasp-lang.dev/blog/2023/07/17/how-we-built-gpt-web-app-generator)。 ## 第 2 步:啟動它🚀 ![圖表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/icff70qgd5ozu23ghgw7.png) 開發產品是一回事,但傳播產品並讓人們使用它則完全是另一回事。在我們建立了 MAGE 並在團隊內對其進行了測試之後,問題是下一步該做什麼?我們如何真正聯繫開發人員並開始接收回饋? ### 社區啟動 - 生命的證明 ![waspularity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nwcmspqyer7hxjysjyjo.png) 由於當時我們已經擁有一個[擁有大約 1,000 名成員的 Wasp 社區](https://discord.gg/rzdnErX),因此我們[發布了 MAGE 作為我們發布週 #3 的一部分](https://wasp-lang.dev/blog/2023/06/22/wasp-launch-week-third#gpt-web-app-generator--friday-waspularity---tutorial-o-thon)。這是一個很好的測試平台,我們可以看到第一個應用程式正在建置。儘管如此,更多的開發人員本可以從更簡單的方式來啟動他們的 React 和 Node.js 專案中受益,但他們卻無法找到 MAGE。 ### 啟動 Product Hunt — 首次「真正」使用 ![mage-ph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w3z5dkjuxn8502699s5a.png) 這就是為什麼我們決定在內部社群啟動後將 MAGE 放在 Product Hunt 上。儘管Product Hunt 不是一個特定於開發工具的平台,並且吸引了來自不同背景的人群,但仍然有很多開發人員在使用它,而且我們[之前有很好的經驗](https://www.producthunt.com/products/wasp-lang-alpha/launches) 與它。 Product Hunt 對於[獲得Wasp 的第一批用戶並在GitHub 上獲得1,000 顆星](https://wasp-lang.dev/blog/2022/09/29/journey-to-1000-gh-stars) 至關重要,因此我們想再試一次。 有些人在發布準備工作上投入了大量精力,需要提前幾個月才能準備好,但我們沒有那個時間,只是想盡快完成。我們要求我們的朋友和社區查看 [MAGE on Product Hunt](https://www.producthunt.com/products/wasp-lang-alpha#gpt-webapp-generator-for-react-node-js) 並提供支持我們在發布當天就進入了當天的前十名產品,後來又躋身本週排名第二的開發者工具! 這就是我們的目標,因為排名前十的產品最終會出現在第二天的電子報中,有超過 100 萬訂閱者閱讀。很快,我們看到建立的應用程式數量顯著增加,新的人開始加入我們的 Discord 社群! ### 有機成長(又稱「無所事事」)階段 在 Product Hunt 推出後,我們放鬆了行銷工作,因為其他與 Wasp 相關的任務趕上了團隊。我們必須為即將到來的[發布週#4](https://wasp-lang.dev/blog/2023/10/13/wasp-launch-week-four)做準備,所以 MAGE 最終被擱置了。在我們決定投入更多資源之前,我們也想看看社區如何接受它。 我們發布了更多後續文章,「[它是如何在後台工作的](https://wasp-lang.dev/blog/2023/07/17/how-we-built-gpt-web-app-generator)”和“[MAGE vs. 一般編碼代理](https://wasp-lang.dev/blog/2023/08/01/smol-ai-vs-wasp-ai)”,獲得平均數量牽引力,但沒有爆炸。我們在 Reddit 和 Hackernews 上也沒有什麼成功,感覺社群已經厭倦了所有的人工智慧內容。 儘管如此,使用 MAGE 建立的應用程式數量持續增長(約 200 個應用程式/天),偶爾會出現小規模爆炸。我們無法真正追蹤用戶來自哪裡 - MAGE 似乎是透過封閉社區和時事通訊中的口碑傳播的。 ### YouTube 和 TikTok 影片 - 病毒式傳播(每天 1,300 個應用程式!) 在我們的第 4 週發布週結束後,我們意識到,在近 2 個月的時間裡,在我們付出最小努力的情況下,MAGE 一直在不斷成長。這向我們表明它具有一定的實際價值,因此我們決定對其進行更多投資。 ![matt_yt_video](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sztjfowul34w6uqwzb56.png) 我們決定與該領域的影響者碰碰運氣。我們不想簡單地支付廣告費用,而是希望與真正對我們正在建立的產品感興趣並且想要客觀地審查 MAGE 的人合作。我們發現 [Matthew Berman](https://www.youtube.com/watch?v=KQrGu8cnwvA&t=2s&ab_channel=MatthewBerman) 涵蓋了 LLM 領域從最新模型到工具的所有內容,他將 MAGE 視為非常適合他的觀眾。 該影片在幾週內就準備好了,當它發佈時,觀看次數很快就達到了約 25,000 次。許多觀眾對透過 Web 介面從單一提示中獲取全端程式碼庫的可能性感到興奮,我們看到使用率和開發人員再次嘗試。 ![tiktok_video](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnfmgt026dvf5yn0a9sm.png) 大約一周後,我們看到建立的應用程式數量再次大幅增加,但無法弄清楚它來自哪裡。我們做了一些搜尋,在TikTok 上找到了一位開發者@techfren,他製作了[一個關於它的短影片](https://www.tiktok.com/@techfren/video/7288306291733269778)(MAGE 甚至最終無法在就是那個!),一天之內瀏覽量猛增至 20 萬次,並迅速走紅。如今,它的瀏覽量已接近 100 萬。 ## 現實 - 所有這些應用程式會發生什麼? 儘管 25,000 個建立的應用程式聽起來令人印象深刻,但退後一步並進一步細分是很好的。 與大多數人工智慧驅動的編碼工具一樣,想要建立自己產品的開發人員和非開發人員都對該領域抱持極大的興趣和好奇心。許多人甚至沒有想要建立的具體專案,但他們熱衷於嘗試一下,看看它是如何運作的。此外,由於法學碩士不是確定性的,因此還沒有任何工具能夠完美執行,並且經常會出現需要手動幹預和編碼知識的小錯誤。 雖然我們對此非常明確(https://wasp-lang.dev/blog/2023/07/10/gpt-web-app-generator#what-kind-of-apps-can-i-build-with-it )和其他[挑戰](https://wasp-lang.dev/blog/2023/07/10/gpt-web-app-generator#challenges)GPT驅動的工具面臨,MAGE仍然吸引了一部分的用戶對建置自己的產品感到興奮,但不精通編碼,需要幫助下載、執行和修復應用程式。另一方面,它是一種非常友好且易於參與 Web 開發和編碼的方式。我們不會阻止非編碼人員嘗試,而是盡可能透明地管理期望。 因此,大約 40% 的所有建立的應用程式都會下載並在本地執行。 ## 結論 事實證明,我們對 MAGE 的實驗非常成功,甚至超越了我們最初的預期。除了許多現有的通用編碼代理之外,高度專業化和結構化的方法可以以低廉的價格產生更好、更一致的結果。 此外,開發人員對啟動全端應用程式的簡單方法(其中包含最佳實踐)感到興奮,並且正在積極尋找這樣的解決方案並在彼此之間共享。 我預計人工智慧輔助的 SaaS 新創公司將成為 Web 開發的未來。如果有人可以使用已經為其應用程式定制的資料模型和 CRUD 邏輯來建立他們的應用程式,那麼為什麼有人會使用通用樣板啟動器呢?另一個問題是誰以及如何具體實現這一點,但我預計未來每個主流框架都會有一個。 ## 祝你好運! 我希望這篇概述對您有所幫助,並讓您了解建立和行銷新的(人工智慧驅動的)開發工具時幕後的情況。請記住,這是我們獨特的經歷,每個故事都是不同的,因此對一切都持保留態度,只選擇對您和您的產品有意義的內容。 我們祝您好運,如果您有任何疑問或想了解 [MAGE](https://usemage.ai/) 和 [Wasp](https://github.com/wasp-lang/wasp)! --- 原文出處:https://dev.to/wasp/how-we-built-a-gpt-web-app-generator-for-react-nodejs-from-idea-to-25000-apps-in-4-months-1aol

React 設計模式 Design Patterns

![](https://refine.ams3.cdn.digitaloceanspaces.com/blog-banners/retool-alternative.png) ## 介紹: React 開發人員可以透過使用設計模式來節省時間和精力,設計模式提供了一種使用經過測試且可信賴的解決方案來解決問題的快速方法。它們支援低耦合的內聚模組,從而幫助 React 開發人員建立可維護、可擴展且高效的應用程式。在本文中,我們將探索 React 設計模式並研究它們如何改進 React 應用程式的開發。 ## 容器和表示模式 容器和表示模式是一種旨在將反應程式碼中的表示邏輯與業務邏輯分離的模式,從而使其模組化、可測試並遵循關注點分離原則。 大多數情況下,在 React 應用程式中,我們需要從後端/儲存取得資料或計算邏輯並在 React 元件上表示該計算的結果。在這些情況下,容器和表示模式大放異彩,因為它可用於將元件分為兩類,即: * 容器元件,充當負責資料取得或計算的元件。 * 表示元件,其工作是將獲取的資料或計算值呈現在 UI(使用者介面)上。 容器和表示模式的範例如下所示: ``` import React, { useEffect } from 'react'; import CharacterList from './CharacterList'; const StarWarsCharactersContainer:React.FC = () => { const [characters, setCharacters] = useState<Character>([]) const [isLoading, setIsLoading] = useState<boolean>(false); const [error, setError] = useState<boolean>(false); const getCharacters = async () => { setIsLoading(true); try { const response = await fetch("https://akabab.github.io/starwars-api/api/all.json"); const data = await response.json(); setIsLoading(false); if (!data) return; setCharacters(data); } catch(err) { setError(true); } finally { setIsLoading(true); } }; useEffect(() => { getCharacters(); }, []); return <CharacterList loading={loading} error={error} characters={characters} />; }; export default StarWarsCharactersContainer; ``` ``` // the component is responsible for displaying the characters import React from 'react'; import { Character } from './types'; interface CharacterListProps { loading: boolean; error: boolean; users: Character[]; } const CharacterList: React.FC<CharacterListProps> = ({ loading, error, characters }) => { if (loading && !error) return <div>Loading...</div>; if (!loading && error) return <div>error occured.unable to load characters</div>; if (!characters) return null; return ( <ul> {characters.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> ); }; export default CharacterList; ``` ## 有 Hooks 的元件組合 Hooks 是 React 16.8 中首次推出的全新功能。從那時起,他們在開發 React 應用程式中發揮了至關重要的作用。掛鉤是基本函數,可授予功能元件存取狀態和生命週期方法(以前僅可用於類別元件)的功能。另一方面,掛鉤可以專門設計來滿足元件要求並具有其他用例。 我們現在可以隔離所有狀態邏輯(一種需要反應性狀態變數的邏輯),並使用自訂掛鉤在元件中組合或使用它。因此,程式碼更加模組化和可測試,因為鉤子鬆散地綁定到元件,因此可以單獨測試。 帶有鉤子的元件組合示例如下所示: ``` // creating a custom hook that fetches star wars characters export const useFetchStarWarsCharacters = () => { const [characters, setCharacters] = useState<Character>([]) const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(false); const controller = new AbortController() const getCharacters = async () => { setIsLoading(true); try { const response = await fetch( "https://akabab.github.io/starwars-api/api/all.json", { method: "GET", credentials: "include", mode: "cors", headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, signal: controller.signal } ); const data = await response.json(); setIsLoading(false); if (!data) return; setCharacters(data); } catch(err) { setError(true); } finally { setIsLoading(true); } }; useEffect(() => { getCharacters(); return () => { controller.abort(); } }, []); return [ characters, isLoading, error ]; }; ``` 建立自訂鉤子後,我們將其導入到我們的 **StarWarsCharactersContainer** 元件中並使用它; ``` // importing the custom hook to a component and fetch the characters import React from 'react'; import { Character } from './types'; import { useFetchStarWarsCharacters } from './useFetchStarWarsCharacters'; const StarWarsCharactersContainer:React.FC = () => { const [ characters, isLoading, error ] = useFetchStarWarsCharacters(); return <CharacterList loading={loading} error={error} characters={characters} />; }; export default StarWarsCharactersContainer; ``` --- <橫幅隨機/> --- ## 使用Reducers進行狀態管理 大多數情況下,處理元件中的許多狀態會導致許多未分組狀態的問題,這可能是處理起來很麻煩且具有挑戰性的。在這種情況下,減速器模式可能是有用的選擇。我們可以使用減速器將狀態分類為某些操作,這些操作在執行時可以變更分組的狀態。 此模式允許使用它的開發人員控制元件和/或掛鉤的狀態管理,讓他們在發送事件時管理狀態變更。 使用減速器模式的範例如下所示: ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbob3gmfxws8k4ti0cyx.png) 在上面的程式碼中,元件調度兩個操作: * “**login**”操作類型會觸發狀態更改,影響三個狀態值,即 **loggedIn**、**user**、**token**。 *“**註銷**”操作只是將狀態重設為其初始值。 ## 提供者的資料管理 提供者模式對於資料管理非常有用,因為它利用上下文 API 透過應用程式的元件樹傳遞資料。這種模式是一種有效的解決支柱鑽井問題的方法,這一直是 React 開發中普遍關注的問題。 為了實現提供者模式,我們首先建立一個提供者元件。 Provider 是 Context 物件提供給我們的一個高階元件。我們可以利用React提供的createContext方法來建構一個Context物件。 ``` export const ThemeContext = React.createContext(null); export function ThemeProvider({ children }) { const [theme, setTheme] = React.useState("light"); return ( <ThemeContext.Provider value={{ theme, setTheme }}> {children} </ThemeContext.Provider> ); } ``` 建立提供者後,我們將使用建立的提供者元件封裝依賴上下文 API 中的資料的元件。 為了從上下文 API 取得資料,我們呼叫 useContext 鉤子,它接受上下文作為參數(在本例中為 **ThemeContext**)。 ``` import { useContext } from 'react'; import { ThemeProvider, ThemeContext } from "../context"; const HeaderSection = () => { <ThemeProvider> <TopNav /> </ThemeProvider>; }; const TopNav = () => { const { theme, setTheme } = useContext(ThemeContext); return ( <div style={{ backgroundColor: theme === "light" ? "#fff" : "#000 " }}> ... </div> ); }; ``` ## 使用 HOC(高階元件)增強元件 高階元件接受一個元件作為參數,並傳回一個注入了附加資料或功能的增壓元件。 React 中 HOC 的可能性是由於 React 更喜歡組合而不是繼承。 高階元件 (HOC) 模式提供了一種增加或修改元件功能的機制,促進元件重複使用和程式碼共用。 HOC 模式的範例如下所示: ``` import React from 'react' const higherOrderComponent = Component => { return class HOC extends React.Component { state = { name: 'John Doe' } render() { return <Component name={this.state.name {...this.props} /> } } const AvatarComponent = (props) => { return ( <div class="flex items-center justify-between"> <div class="rounded-full bg-red p-4"> {props.name} </div> <div> <p>I am a {props.description}.</p> </div> </div> ) } const SampleHOC = higherOrderComponent(AvatarComponent); const App = () => { return ( <div> <SampleHOC description="Frontend Engineer" /> </div> ) } export default App; ``` 在上面的程式碼中, **<AvatarComponent/>** 由 **higherOrderComponent** 提供 props,它將在內部使用。 ## 複合元件 複合元件模式是一種 React 設計模式,用於管理由子元件組成的父元件。 這種模式背後的原理是將父元件分解為更小的元件,然後使用 props、上下文或其他反應資料管理技術來管理這些較小元件之間的互動。 當需要建立由較小元件組成的可重複使用、多功能元件時,這種模式會派上用場。它使開發人員能夠建立複雜的 UI 元件,這些元件可以輕鬆自訂和擴展,同時保持清晰簡單的程式碼結構。 複合元件模式的用例範例如下所示: ``` import React, { createContext, useState } from 'react'; const ToggleContext = createContext(); function Toggle({ children }) { const [on, setOn] = useState(false); const toggle = () => setOn(!on); return ( <ToggleContext.Provider value={{ on, toggle }}> {children} </ToggleContext.Provider> ); } Toggle.On = function ToggleOn({ children }) { const { on } = useContext(ToggleContext); return on ? children : null; } Toggle.Off = function ToggleOff({ children }) { const { on } = useContext(ToggleContext); return on ? null : children; } Toggle.Button = function ToggleButton(props) { const { on, toggle } = useContext(ToggleContext); return <button onClick={toggle} {...props} />; } function App() { return ( <Toggle> <Toggle.On>The button is on</Toggle.On> <Toggle.Off>The button is off</Toggle.Off> <Toggle.Button>Toggle</Toggle.Button> </Toggle> ); } ``` ## 道具組合 這需要從幾個相關的 props 建立一個物件,並將其作為單個 props 傳遞給元件。 這種模式允許我們清理程式碼並使管理 props 變得更簡單,當我們想要將大量相關屬性傳遞給元件時,它特別有用。 ``` import React from 'react'; function P(props) { const { color, size, children, ...rest } = props; return ( <p style={{ color, fontSize: size }} {...rest}> { children } </p> ); } function App() { const paragraphProps = { color: "red", size: "20px", lineHeight: "22px" }; return <P {...paragraphProps}>This is a P</P>; } ``` ## 受控輸入 受控輸入模式可用於處理輸入欄位。此模式涉及使用事件處理程序在輸入欄位的值發生變更時更新元件狀態,以及將輸入欄位的目前值儲存在元件狀態中。 由於React 控制元件的狀態和行為,因此該模式使程式碼比不受控制的輸入模式更具可預測性和可讀性,後者不使用元件的狀態,而是直接透過DOM(文件物件模型)對其進行控制。 受控輸入模式的用例範例如下所示: ``` import React, { useState } from 'react'; function ControlledInput() { const [inputValue, setInputValue] = useState(''); const handleChange = (event) => { setInputValue(event.target.value); }; return ( <input type="text" value={inputValue} onChange={handleChange} /> ); } ``` ## 使用forwardRefs 管理自訂元件 稱為 ForwardRef 的高階元件將另一個元件作為輸入並輸出一個傳遞原始元件引用的新元件。透過這樣做,子元件的 ref(可用於檢索底層 DOM 節點或元件實例)可供父元件存取。 當建立與第三方程式庫或應用程式中的另一個自訂元件互動的自訂元件時,在工作流程中包含 ForwardRef 模式非常有幫助。透過授予對庫的 DOM 節點或另一個元件的 DOM 實例的存取權限,它有助於將此類元件的控制權轉移給您。 forwardRef 模式的用例範例如下所示: ``` import React from "react"; const CustomInput = React.forwardRef((props, ref) => ( <input type="text" {...props} ref={ref} /> )); const ParentComponent = () => { const inputRef = useRef(null); useEffect(() => { inputRef.current.focus(); }, []); return <CustomInput ref={inputRef} />; }; ``` 在上面的程式碼中,我們使用「forwardRefs」從元件「<ParentComponent/>」觸發了另一個元件「<CustomInput/>」的焦點。 # 結論 我們在本文中討論了 React 設計模式,包括高階元件、容器呈現元件模式、複合元件、受控元件等等。透過將這些設計模式和最佳實踐合併到您的 React 專案中,您可以提高程式碼質量,促進團隊協作,並使您的應用程式更具可擴展性、靈活性和可維護性。 --- 原文出處:https://dev.to/refine/react-design-patterns-230o

44 個 React 前端面試問題

原文出處:https://dev.to/m_midas/44-react-frontend-interview-questions-2o63 ## 介紹 在面試 React 前端開發人員職位時,為技術問題做好充分準備至關重要。 React 已經成為建立使用者介面最受歡迎的 JavaScript 程式庫之一,雇主通常專注於評估候選人對 React 核心概念、最佳實踐和相關技術的理解。在本文中,我們將探討 React 前端開發人員面試期間常見問題的完整清單。透過熟悉這些問題及其答案,您可以增加成功的機會並展示您在 React 開發方面的熟練程度。因此,讓我們深入探討您應該準備好在 React 前端開發人員面試中解決的關鍵主題。 ![](https://media.giphy.com/media/AYECTMLNS4o67dCoeY/giphy.gif) ### 1.你知道哪些React hooks? - `useState`:用於管理功能元件中的狀態。 - `useEffect`:用於在功能元件中執行副作用,例如取得資料或訂閱事件。 - `useContext`:用於存取功能元件內的 React 上下文的值。 - `useRef`:用於建立對跨渲染持續存在的元素或值的可變引用。 - `useCallback`:用於記憶函數以防止不必要的重新渲染。 - `useMemo`:用於記憶值,透過快取昂貴的計算來提高效能。 - `useReducer`:用於使用reducer函數管理狀態,類似於Redux的工作方式。 - `useLayoutEffect`:與 useEffect 類似,但效果在所有 DOM 變更後同步運作。 這些鉤子提供了強大的工具來管理狀態、處理副作用以及重複使用 React 功能元件中的邏輯。 [了解更多](https://react.dev/reference/react) ### 2.什麼是虛擬 DOM? 虛擬 DOM 是 React 中的一個概念,其中建立實際 DOM(文件物件模型)的輕量級虛擬表示並將其儲存在記憶體中。它是一種用於優化 Web 應用程式效能的程式設計技術。 當 React 元件的資料或狀態發生變更時,虛擬 DOM 會被更新,而不是直接操作真實 DOM。然後,虛擬 DOM 計算元件的先前狀態和更新狀態之間的差異,稱為「比較」過程。 一旦辨識出差異,React 就會有效地僅更新真實 DOM 的必要部分以反映變更。這種方法最大限度地減少了實際 DOM 操作的數量,並提高了應用程式的整體效能。 透過使用虛擬 DOM,React 提供了一種建立動態和互動式使用者介面的方法,同時確保最佳效率和渲染速度。 ### 3. 如何渲染元素陣列? 要渲染元素陣列,可以使用“map()”方法迭代該陣列並傳回一個新的 React 元素陣列。 ``` const languages = [ "JavaScript", "TypeScript", "Python", ]; function App() { return ( <div> <ul>{languages.map((language) => <li>{language}</li>)}</ul> </div> ); } ``` [了解更多](https://react.dev/learn/rendering-lists) ### 4. 受控元件和非受控元件有什麼不同? 受控元件和非受控元件之間的區別在於**它們如何管理和更新其狀態**。 受控元件是狀態由 React 控制的元件。元件接收其當前值並透過 props 更新它。當值改變時它也會觸發回調函數。這意味著該元件不儲存其自己的內部狀態。相反,父元件管理該值並將其傳遞給受控元件。 ``` import { useState } from 'react'; function App() { const [value, setValue] = useState(''); return ( <div> <h3>Controlled Component</h3> <input name="name" value={name} onChange={(e) => setValue(e.target.value)} /> <button onClick={() => console.log(value)}>Get Value</button> </div> ); } ``` 另一方面,不受控制的元件使用 refs 或其他方法在內部管理自己的狀態。它們獨立儲存和更新狀態,不依賴 props 或回呼。父元件對不受控元件的狀態控制較少。 ``` import { useRef } from 'react'; function App() { const inputRef = useRef(null); return ( <div className="App"> <h3>Uncontrolled Component</h3> <input type="text" name="name" ref={inputRef} /> <button onClick={() => console.log(inputRef.current.value)}>Get Value</button> </div> ); } ``` [了解更多](https://react.dev/learn/sharing-state- Between-components#driven-and-uncontrol-components) ### 5. 基於類別的 React 元件和函數式 React 元件有什麼不同? 基於類別的元件和函數式元件之間的主要區別在於**它們的定義方式以及它們使用的語法。** 基於類別的元件被定義為 ES6 類別並擴展了 `React.Component` 類別。他們使用「render」方法傳回定義元件輸出的 JSX (JavaScript XML)。類別元件可以透過「this.state」和「this.setState()」存取元件生命週期方法和狀態管理。 ``` class App extends React.Component { state = { value: 0, }; handleAgeChange = () => { this.setState({ value: this.state.value + 1 }); }; render() { return ( <> <p>Value is {this.state.value}</p> <button onClick={this.handleAgeChange}> Increment value </button> </> ); } } ``` 另一方面,函數元件被定義為簡單的 JavaScript 函數。他們接受 props 作為參數並直接返回 JSX。功能元件無權存取生命週期方法或狀態。然而,隨著 React 16.8 中 React Hooks 的引入,功能元件現在可以管理狀態並使用其他功能,例如上下文和效果。 ``` import { useState } from 'react'; const App = () => { const [value, setValue] = useState(0); const handleAgeChange = () => { setValue(value + 1); }; return ( <> <p>Value is {value}</p> <button onClick={handleAgeChange}> Increment value </button> </> ); } ``` 一般來說,功能元件被認為更簡單、更容易閱讀和測試。建議盡可能使用函數式元件,除非有特定需要基於類別的元件。 ### 6. 元件的生命週期方法有哪些? 生命週期方法是一種掛鉤元件生命週期不同階段的方法,可讓您在特定時間執行特定程式碼。 以下是主要生命週期方法的清單: 1. `constructor`:這是建立元件時呼叫的第一個方法。它用於初始化狀態和綁定事件處理程序。在功能元件中,您可以使用“useState”鉤子來實現類似的目的。 2. `render`:此方法負責渲染 JSX 標記並傳回螢幕上要顯示的內容。 3. `componentDidMount`:元件在 DOM 中渲染後立即呼叫該方法。它通常用於初始化任務,例如 API 呼叫或設定事件偵聽器。 4. `componentDidUpdate`:當元件的 props 或 state 改變時呼叫該方法。它允許您執行副作用、根據更改更新元件或觸發其他 API 呼叫。 5. `componentWillUnmount`:在元件從 DOM 刪除之前呼叫此方法。它用於清理在`componentDidMount`中設定的任何資源,例如刪除事件偵聽器或取消計時器。 一些生命週期方法,例如“componentWillMount”、“componentWillReceiveProps”和“componentWillUpdate”,已被棄用或替換為替代方法或掛鉤。 至於“this”,它指的是類別元件的當前實例。它允許您存取元件內的屬性和方法。在函數式元件中,不使用“this”,因為函數未綁定到特定實例。 ### 7. 使用 useState 有什麼特色? `useState` 傳回一個狀態值和一個更新它的函數。 ``` const [value, setValue] = useState('Some state'); ``` 在初始渲染期間,傳回的狀態與作為第一個參數傳遞的值相符。 `setState` 函數用於更新狀態。它採用新的狀態值作為參數,並**對元件的重新渲染進行排隊**。 `setState` 函數也可以接受回呼函數作為參數,該函數將先前的狀態值作為參數。 [了解更多](https://react.dev/reference/react/useState) ### 8. 使用 useEffect 有什麼特別之處? `useEffect` 鉤子可讓您在功能元件中執行副作用。 稱為 React 渲染階段的功能元件的主體內部不允許突變、訂閱、計時器、日誌記錄和其他副作用。這可能會導致用戶介面中出現令人困惑的錯誤和不一致。 相反,建議使用 useEffect。傳遞給 useEffect 的函數將在渲染提交到螢幕後執行,或者如果您傳遞一組依賴項作為第二個參數,則每次依賴項之一發生變更時都會呼叫該函數。 ``` useEffect(() => { console.log('Logging something'); }, []) ``` [了解更多](https://react.dev/reference/react/useEffect) ### 9. 如何追蹤功能元件的卸載? 通常,「useEffect」會建立在元件離開畫面之前需要清理或重設的資源,例如訂閱或計時器辨識碼。 為了做到這一點,傳遞給`useEffect`的函數可以傳回一個**清理函數**。清理函數在元件從使用者介面刪除之前執行,以防止記憶體洩漏。此外,如果元件渲染多次(通常是這種情況),則在執行下一個效果之前會清除上一個效果。 ``` useEffect(() => { function handleChange(value) { setValue(value); } SomeAPI.doFunction(id, handleChange); return function cleanup() { SomeAPI.undoFunction(id, handleChange); }; }) ``` ### 10. React 中的 props 是什麼? Props 是從父元件傳遞給元件的資料。道具 是唯讀的,無法更改。 ``` // Parent component const Parent = () => { const data = "Hello, World!"; return ( <div> <Child data={data} /> </div> ); }; // Child component const Child = ({ data }) => { return <div>{data}</div>; }; ``` [了解更多](https://react.dev/learn/passing-props-to-a-component) ### 11. 什麼是狀態管理器?您曾與哪些狀態管理器合作過或認識哪些狀態管理器? 狀態管理器是幫助管理應用程式狀態的工具或程式庫。它提供了一個集中式儲存或容器來儲存和管理可由應用程式中的不同元件存取和更新的資料。 狀態管理器可以解決幾個問題。首先,將資料和與其相關的邏輯與元件分開是一個很好的做法。其次,當使用本機狀態並在元件之間傳遞它時,由於元件可能存在深層嵌套,程式碼可能會變得複雜。透過擁有全域存儲,我們可以存取和修改來自任何元件的資料。 除了 React Context,Redux 或 MobX 通常用作狀態管理庫。 [了解更多](https://mobx.js.org/README.html) [了解更多](https://redux-toolkit.js.org/) ### 12. 在什麼情況下可以使用本地狀態,什麼時候應該使用全域狀態? 如果本機狀態僅在一個元件中使用且不打算將其傳遞給其他元件,則建議使用本機狀態。本地狀態也用在表示清單中單一專案的元件中。但是,如果元件分解涉及嵌套元件且資料沿層次結構傳遞,則最好使用全域狀態。 ### 13. Redux中的reducer是什麼,它需要哪些參數? 減速器是一個純函數,它將狀態和操作作為參數。在減速器內部,我們追蹤接收到的操作的類型,並根據它修改狀態並傳回一個新的狀態物件。 ``` export default function appReducer(state = initialState, action) { // The reducer normally looks at the action type field to decide what happens switch (action.type) { // Do something here based on the different types of actions default: // If this reducer doesn't recognize the action type, or doesn't // care about this specific action, return the existing state unchanged return state } } ``` [了解更多](https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers) ### 14. 什麼是操作以及如何更改 Redux 中的狀態? Action 是一個簡單的 JavaScript 物件,必須有一個字段 一種。 ``` { type: "SOME_TYPE" } ``` 您也可以選擇新增一些資料作為**有效負載**。為了 改變狀態,需要呼叫我們傳遞給它的調度函數 行動 ``` { type: "SOME_TYPE", payload: "Any payload", } ``` [了解更多](https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers) ### 15. Redux 實作了哪一種模式? Redux 實作了 **Flux 模式**,這是應用程式可預測的狀態管理模式。它透過引入單向資料流和應用程式狀態的集中儲存來幫助管理應用程式的狀態。 [了解更多](https://www.newline.co/fullstack-react/30-days-of-react/day-18/#:~:text=Flux%20is%20a%20pattern%20for,default% 20method %20用於%20處理%20資料。) ### 16. Mobx 實作哪一種模式? Mobx 實作了**觀察者模式**,也稱為發布-訂閱模式。 [了解更多](https://www.patterns.dev/posts/observer-pattern) ### 17. 使用 Mobx 的特徵是什麼? Mobx 提供了「observable」和「compulated」等裝飾器來定義可觀察狀態和反應函數。以action修飾的動作用於修改狀態,確保追蹤所有變更。 Mobx 還提供自動依賴追蹤、不同類型的反應、對反應性的細粒度控制,以及透過 mobx-react 套件與 React 無縫整合。總體而言,Mobx 透過根據可觀察狀態的變化自動執行更新過程來簡化狀態管理。 ### 18.如何存取Mobx狀態下的變數? 您可以透過使用「observable」裝飾器將變數定義為可觀察來存取狀態中的變數。這是一個例子: ``` import { observable, computed } from 'mobx'; class MyStore { @observable myVariable = 'Hello Mobx'; @computed get capitalizedVariable() { return this.myVariable.toUpperCase(); } } const store = new MyStore(); console.log(store.capitalizedVariable); // Output: HELLO MOBX store.myVariable = 'Hi Mobx'; console.log(store.capitalizedVariable); // Output: HI MOBX ``` 在此範例中,使用“observable”裝飾器將“myVariable”定義為可觀察物件。然後,您可以使用“store.myVariable”存取該變數。對「myVariable」所做的任何變更都會自動觸發相關元件或反應的更新。 [了解更多](https://mobx.js.org/actions.html) ### 19.Redux 和 Mobx 有什麼差別? Redux 是一個更簡單、更固執己見的狀態管理庫,遵循嚴格的單向資料流並促進不變性。它需要更多的樣板程式碼和顯式更新,但與 React 具有出色的整合。 另一方面,Mobx 提供了更靈活、更直觀的 API,且樣板程式碼更少。它允許您直接修改狀態並自動追蹤更改以獲得更好的性能。 Redux 和 Mobx 之間的選擇取決於您的特定需求和偏好。 ### 20.什麼是 JSX? 預設情況下,以下語法用於在 React 中建立元素。 ``` const someElement = React.createElement( 'h3', {className: 'title__value'}, 'Some Title Value' ); ``` 但我們已經習慣這樣看 ``` const someElement = ( <h3 className='title__value'>Some Title Value</h3> ); ``` 這正是標記所謂的 jsx。這是一種語言的擴展 簡化對程式碼和開發的認知 [了解更多](https://react.dev/learn/writing-markup-with-jsx#jsx-putting-markup-into-javascript) ### 21.什麼是道具鑽探? Props 鑽取是指透過多層嵌套元件傳遞 props 的過程,即使某些中間元件不直接使用這些 props。這可能會導致程式碼結構複雜且繁瑣。 ``` // Parent component const Parent = () => { const data = "Hello, World!"; return ( <div> <ChildA data={data} /> </div> ); }; // Intermediate ChildA component const ChildA = ({ data }) => { return ( <div> <ChildB data={data} /> </div> ); }; // Leaf ChildB component const ChildB = ({ data }) => { return <div>{data}</div>; }; ``` 在此範例中,「data」屬性從 Parent 元件傳遞到 ChildA,然後從 ChildA 傳遞到 ChildB,即使 ChildA 不會直接使用該屬性。當存在許多層級的嵌套或當元件樹中更靠下的元件需要存取資料時,這可能會成為問題。它會使程式碼更難維護和理解。 可以透過使用其他模式(如上下文或狀態管理庫(如 Redux 或 MobX))來緩解 Props 鑽探。這些方法允許元件存取資料,而不需要透過每個中間元件傳遞 props。 ### 22. 如何有條件地渲染元素? 您可以使用任何條件運算符,包括三元。 ``` return ( <div> {isVisible && <span>I'm visible!</span>} </div> ); ``` ``` return ( <div> {isOnline ? <span>I'm online!</span> : <span>I'm offline</span>} </div> ); ``` ``` if (isOnline) { element = <span>I'm online!</span>; } else { element = <span>I'm offline</span>; } return ( <div> {element} </div> ); ``` [了解更多](https://react.dev/learn/conditional-rendering) ### 23. useMemo 的用途是什麼?它是如何運作的? `useMemo` 用於緩存和記憶 計算結果。 傳遞建立函數和依賴項陣列。只有當任何依賴項的值發生變更時,`useMemo` 才會重新計算記憶值。此優化有助於避免 每次渲染都需要昂貴的計算。 使用第一個參數,函數接受執行計算的回調,使用第二個依賴項陣列,僅當至少一個依賴項發生變更時,該函數才會重新執行計算。 ``` const memoValue = useMemo(() => computeFunc(paramA, paramB), [paramA, paramB]); ``` [了解更多](https://react.dev/reference/react/useMemo) ### 24. useCallback 的用途是什麼?它是如何運作的? `useCallback` 掛鉤將傳回回呼的記憶版本,僅當依賴項之一的值發生變更時,該版本才會變更。 當將回調傳遞給依賴連結相等性來防止不必要的渲染的最佳化子元件時,這非常有用。 ``` const callbackValue = useCallback(() => computeFunc(paramA, paramB), [paramA, paramB]); ``` [了解更多](https://react.dev/reference/react/useCallback) ### 25. useMemo 和 useCallback 有什麼不同? 1. `useMemo` 用於儲存計算結果,而 `useCallback` 用於儲存函數本身。 2. `useMemo` 快取計算值,如果依賴項沒有改變,則在後續渲染時傳回它。 3. `useCallback` 快取函數本身並傳回相同的實例,除非相依性發生變更。 ### 26.什麼是 React Context? React Context 是一項功能,它提供了一種透過元件樹傳遞資料的方法,而無需在每個層級手動傳遞 props。它允許您建立一個全域狀態,樹中的任何元件都可以存取該狀態,無論其位置如何。當您需要在未透過 props 直接連接的多個元件之間共用資料時,上下文就非常有用。 React Context API 由三個主要部分組成: 1. `createContext`:此函數用於建立一個新的上下文物件。 2. `Context.Provider`:該元件用於向上下文提供值。它包裝了需要存取該值的元件。 3. `Context.Consumer` 或 `useContext` 鉤子:此元件或鉤子用於使用上下文中的值。它可以在上下文提供者內的任何元件中使用。 透過使用 React Context,您可以避免道具鑽探(透過多個層級的元件傳遞道具)並輕鬆管理更高層級的狀態,使您的程式碼更有組織性和效率。 [了解更多](https://react.dev/learn/passing-data-deeply-with-context) ### 27. useContext 的用途是什麼?它是如何運作的? 在典型的 React 應用程式中,資料使用 props 從上到下(從父元件到子元件)傳遞。但這樣的使用方法對於某些類型的道具來說可能過於繁瑣 (例如,所選語言、UI 主題),必須傳遞給應用程式中的許多元件。上下文提供了一種在元件之間共享此類資料的方法,而無需明確傳遞 props 樹的每一層。 呼叫 useContext 的元件將始終在以下情況下重新渲染: 上下文值發生變化。如果重新渲染元件的成本很高,您可以使用記憶來優化它。 ``` const App = () => { const theme = useContext(ThemeContext); return ( <div style={{ color: theme.palette.primary.main }}> Some div </div> ); } ``` [了解更多](https://react.dev/reference/react/useContext) ### 28. useRef 的用途是什麼?它是如何運作的? `useRef` 傳回一個可修改的 ref 物件,一個屬性。其中的當前值由傳遞的參數初始化。傳回的物件將在元件的整個生命週期內持續存在,並且不會因渲染而改變。 通常的用例是以命令式存取後代 風格。 IE。使用 ref,我們可以明確引用 DOM 元素。 ``` const App = () => { const inputRef = useRef(null); const buttonClick = () => { inputRef.current.focus(); } return ( <> <input ref={inputRef} type="text" /> <button onClick={buttonClick}>Focus on input tag</button> </> ) } ``` [了解更多](https://react.dev/reference/react/useRef) ### 29. 什麼是 React.memo()? `React.memo()` 是一個高階元件。如果您的元件始終使用不變的 props 渲染相同的內容,您可以將其包裝在「React.memo()」呼叫中,以在某些情況下提高效能,從而記住結果。這意味著 React 將使用上次渲染的結果,避免重新渲染。 `React.memo()` 只影響 props 的變更。如果一個功能元件被包裝在 React.memo 中並使用 useState、useReducer 或 useContext,那麼當狀態或上下文發生變化時,它將重新渲染。 ``` import { memo } from 'react'; const MemoComponent = memo(MemoComponent = (props) => { // ... }); ``` [了解更多](https://react.dev/reference/react/memo) ### 30.React Fragment是什麼? 從元件傳回多個元素是 React 中的常見做法。片段可讓您形成子元素列表,而無需在 DOM 中建立不必要的節點。 ``` <> <OneChild /> <AnotherChild /> </> // or <React.Fragment> <OneChild /> <AnotherChild /> </React.Fragment> ``` [了解更多](https://react.dev/reference/react/Fragment) ### 31.什麼是 React Reconciliation? 協調是一種 React 演算法,用於區分一棵元素樹與另一棵元素樹,以確定需要替換的部分。 協調是我們過去所說的虛擬 DOM 背後的演算法。這個定義聽起來是這樣的:當你渲染一個 React 應用程式時,描述該應用程式的元素樹是在保留的記憶體中產生的。然後這棵樹被包含在渲染環境中——例如,瀏覽器應用程式,它被翻譯成一組 DOM 操作。當應用程式狀態更新時,會產生一棵新樹。將新樹與前一棵樹進行比較,以便準確計算並啟用重繪更新的應用程式所需的操作。 [了解更多](https://react.dev/learn/preserving-and-resetting-state) ### 32.為什麼使用map()時需要列表中的鍵? 這些鍵可幫助 React 確定哪些元素已更改, 新增或刪除。必須指定它們以便 React 可以匹配 隨著時間的推移陣列元素。選擇鍵的最佳方法是使用能夠清楚區分清單專案與其鄰居的字串。大多數情況下,您將使用資料中的 ID 作為金鑰。 ``` const languages = [ { id: 1, lang: "JavaScript", }, { id: 2, lang: "TypeScript", }, { id: 3, lang: "Python", }, ]; const App = () => { return ( <div> <ul>{languages.map((language) => ( <li key={`${language.id}_${language.lang}`}>{language.lang}</li> ))} </ul> </div> ); } ``` [了解更多](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) ### 33. 如何在 Redux Thunk 中處理非同步操作? 要使用 Redux Thunk,您需要將其作為中間件導入。動作建立者不僅應該傳回一個物件,還應該傳回以調度為參數的函數。 ``` export const addUser = ({ firstName, lastName }) => { return dispatch => { dispatch(addUserStart()); } axios.post('https://jsonplaceholder.typicode.com/users', { firstName, lastName, completed: false }) .then(res => { dispatch(addUserSuccess(res.data)); }) .catch(error => { dispatch(addUserError(error.message)); }) } ``` [了解更多](https://redux.js.org/usage/writing-logic-thunks) ### 34.如何追蹤功能元件中物件欄位的變化? 為此,您需要使用“useEffect”掛鉤並將物件的欄位作為依賴項陣列傳遞。 ``` useEffect(() => { console.log('Changed!') }, [obj.someField]) ``` ### 35.如何存取DOM元素? 引用是使用 React.createRef() 或 useRef() 鉤子建立的,並透過 ref 屬性附加到 React 元素。透過存取已建立的引用,我們可以使用「ref.current」來存取 DOM 元素。 ``` const App = () => { const myRef = useRef(null); const handleClick = () => { console.log(myRef.current); // Accessing the DOM element }; return ( <div> <input type="text" ref={myRef} /> <button onClick={handleClick}>Click Me</button> </div> ); } export default App; ``` ### 36.什麼是自訂鉤子? 自訂鉤子是一個允許您在不同元件之間重複使用邏輯的功能。它是一種封裝可重複使用邏輯的方法,以便可以在多個元件之間輕鬆共用和重複使用。自訂掛鉤是通常以 **use ** 開頭的函數,並且可以根據需要呼叫其他掛鉤。 [了解更多](https://react.dev/learn/reusing-logic-with-custom-hooks) ### 37.什麼是公共API? 在索引檔案的上下文中,公共 API 通常是指向外部模組或元件公開並可存取的介面或函數。 以下是表示公共 API 的索引檔案的程式碼範例: ``` // index.js export function greet(name) { return `Hello, ${name}!`; } export function calculateSum(a, b) { return a + b; } ``` 在此範例中,index.js 檔案充當公共 API,其中導出函數“greet()”和“calculateSum()”,並且可以透過匯入它們從其他模組存取它們。其他模組可以導入並使用這些函數作為其實現的一部分: ``` // main.js import { greet, calculateSum } from './index.js'; console.log(greet('John')); // Hello, John! console.log(calculateSum(5, 3)); // 8 ``` 透過從索引檔案匯出特定函數,我們定義了模組的公共 API,允許其他模組使用這些函數。 ### 38. 建立自訂鉤子的規則是什麼? 1. 鉤子名稱以「use」開頭。 2. 如果需要,使用現有的鉤子。 3. 不要有條件地呼叫鉤子。 4. 將可重複使用邏輯提取到自訂掛鉤中。 5. 自訂hook必須是純函數。 6. 自訂鉤子可以傳回值或其他鉤子。 7. 描述性地命名自訂掛鉤。 [了解更多](https://react.dev/learn/reusing-logic-with-custom-hooks) ### 39.什麼是SSR(伺服器端渲染)? 伺服器端渲染(SSR)是一種用於在伺服器上渲染頁面並將完整渲染的頁面傳送到客戶端進行顯示的技術。它允許伺服器產生網頁的完整 HTML 標記(包括其動態內容),並將其作為對請求的回應傳送到客戶端。 在傳統的用戶端渲染方法中,用戶端接收最小的 HTML 頁面,然後向伺服器發出額外的資料和資源請求,這些資料和資源用於在客戶端渲染頁面。這可能會導致初始頁面載入時間變慢,並對搜尋引擎優化 (SEO) 產生負面影響,因為搜尋引擎爬蟲很難對 JavaScript 驅動的內容建立索引。 透過 SSR,伺服器透過執行必要的 JavaScript 程式碼來產生最終的 HTML 來負責渲染網頁。這意味著客戶端從伺服器接收完全呈現的頁面,從而減少了額外資源請求的需要。 SSR 縮短了初始頁面載入時間,並允許搜尋引擎輕鬆索引內容,從而實現更好的 SEO。 SSR 通常用於框架和函式庫中,例如用於 React 的 Next.js 和用於 Vue.js 的 Nuxt.js,以啟用伺服器端渲染功能。這些框架為您處理伺服器端渲染邏輯,讓實作 SSR 變得更加容易。 ### 40.使用SSR有什麼好處? 1. **改進初始載入時間**:SSR 允許伺服器將完全渲染的 HTML 頁面傳送到客戶端,從而減少客戶端所需的處理量。這可以縮短初始載入時間,因為使用者可以更快地看到完整的頁面。 2. **SEO友善**:搜尋引擎可以有效地抓取和索引SSR頁面的內容,因為完全渲染的HTML在初始回應中可用。這提高了搜尋引擎的可見度並有助於更好的搜尋排名。 3. **可存取性**:SSR 確保禁用 JavaScript 或使用輔助技術的使用者可以存取內容。透過在伺服器上產生 HTML,SSR 為所有使用者提供可靠且易於存取的使用者體驗。 4. **低頻寬環境下的效能**:SSR減少了客戶端需要下載的資料量,有利於低頻寬或高延遲環境下的使用者。這對於行動用戶或網路連線速度較慢的用戶尤其重要。 雖然 SSR 提供了這些優勢,但值得注意的是,與客戶端渲染方法相比,它可能會帶來更多的伺服器負載和維護複雜性。應仔細考慮快取、可擴展性和伺服器端渲染效能最佳化等因素。 ### 41.你知道Next.js的主要功能有哪些? 1. `getStaticProps`:此方法用於在建置時取得資料並將頁面預先渲染為靜態 HTML。它確保資料在建置時可用,並且不會因後續請求而更改。 ``` export async function getStaticProps() { const res = await fetch('https://api.example.com/data'); const data = await res.json(); return { props: { data } }; } ``` 2. `getServerSideProps`:此方法用於在每個請求上取得資料並在伺服器上預先渲染頁面。當您需要取得可能經常變更或特定於使用者的資料時,可以使用它。 ``` export async function getServerSideProps() { const res = await fetch('https://api.example.com/data'); const data = await res.json(); return { props: { data } }; } ``` 3. `getStaticPaths`:此方法在動態路由中使用,用於指定建置時應預先渲染的路徑清單。它通常用於獲取帶有參數的動態路由的資料。 ``` export async function getStaticPaths() { const res = await fetch('https://api.example.com/posts'); const posts = await res.json(); const paths = posts.map((post) => ({ params: { id: post.id } })); return { paths, fallback: false }; } ``` [了解更多](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating) ### 42.什麼是 Linters? Linters 是用來檢查原始程式碼是否有潛在錯誤、錯誤、風格不一致和可維護性問題的工具。它們可幫助執行編碼標準並確保整個程式碼庫的程式碼品質和一致性。 Linters 的工作原理是掃描原始程式碼並將其與一組預先定義的規則或指南進行比較。這些規則可以包括語法和格式約定、最佳實踐、潛在錯誤和程式碼異味。當 linter 發現違反規則時,它會產生警告或錯誤,突出顯示需要注意的特定行或多行程式碼。 使用 linter 可以帶來幾個好處: 1. **程式碼品質**:Linter 有助於辨識和防止潛在的錯誤、程式碼異味和反模式,從而提高程式碼品質。 2. **一致性**:Linter 強制執行編碼約定和風格指南,確保整個程式碼庫的格式和程式碼結構一致,即使多個開發人員正在處理同一個專案時也是如此。 3. **可維護性**:透過儘早發現問題並促進良好的編碼實踐,linter 有助於程式碼的可維護性,使程式碼庫更容易理解、修改和擴展。 4. **效率**:Linter 可以透過自動化程式碼審查流程並在常見錯誤在開發或生產過程中引起問題之前捕獲它們來節省開發人員的時間。 一些流行的 linter 包括用於 JavaScript 的 ESLint 以及用於 CSS 和 Sass 的 Stylelint。 [了解更多](https://eslint.org/docs/latest/use/getting-started) ### 43.你知道哪些 React 架構解決方案? 有多種用於建立 React 專案的架構解決方案和模式。一些受歡迎的包括: 1. **MVC(模型-視圖-控制器)**:MVC 是一種傳統的架構模式,它將應用程式分為三個主要元件 - 模型、視圖和控制器。 React 可以在 View 層中使用來渲染 UI,而其他程式庫或框架可以用於 Model 和 Controller 層。 2. **Flux**:Flux是Facebook專門針對React應用程式所推出的應用架構。它遵循單向資料流,其中資料沿著單一方向流動,從而更容易理解和除錯應用程式的狀態變更。 3. **原子設計**:原子設計並不是React特有的,而是將UI分割成更小、可重複使用元件的設計方法。它鼓勵建立小型、獨立且可以組合以建立更複雜的 UI 的元件。 4. **容器和元件模式**:此模式將表示(元件)與邏輯和狀態管理(容器)分開。元件負責渲染 UI,而容器則處理業務邏輯和狀態管理。 5. **功能切片設計**:它是一種用於組織和建構 React 應用程式的現代架構方法。它旨在透過根據功能或模組劃分應用程式程式碼庫來解決可擴展性、可維護性和可重用性的挑戰。 ### 44.什麼是特徵切片設計? 它是一種用於組織和建立 React 應用程式的現代架構方法。它旨在透過根據功能或模組劃分應用程式程式碼庫來解決可擴展性、可維護性和可重用性的挑戰。 在功能切片設計中,應用程式的每個功能或模組都組織到一個單獨的目錄中,其中包含所有必要的元件、操作、reducers 和其他相關檔案。這有助於保持程式碼庫的模組化和隔離性,使其更易於開發、測試和維護。 功能切片設計促進了關注點的清晰分離,並將功能封裝在各個功能中。這允許不同的團隊或開發人員獨立地處理不同的功能,而不必擔心衝突或依賴性。 ![功能切片設計](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/amysbtftfjkuss87yu8v.png) **我強烈建議點擊“了解更多”按鈕以了解功能切片設計** [了解更多](https://dev.to/m_midas/feature-sliced-design-the-best-frontend-architecture-4noj) ## 了解更多 如果您還沒有閱讀過,我強烈建議您閱讀我關於前端面試問題的其餘文章。 https://dev.to/m_midas/52-frontend-interview-questions-javascript-59h6 https://dev.to/m_midas/41-frontend-interview-questions-css-4imc https://dev.to/m_midas/15-most-common-frontend-interview-questions-4njp ## 結論 總之,面試 React 前端開發人員職位需要對框架的核心概念、原理和相關技術有深入的了解。透過準備本文中討論的問題,您可以展示您的 React 知識並展示您建立高效且可維護的使用者介面的能力。請記住,不僅要專注於記住答案,還要理解基本概念並能夠清楚地解釋它們。 此外,請記住,面試不僅涉及技術方面,還旨在展示您解決問題的能力、溝通能力以及團隊合作能力。透過將技術專業知識與強大的整體技能相結合,您將具備在 React 前端開發人員面試中脫穎而出的能力,並在這個令人興奮且快速發展的領域找到您夢想的工作。 祝你好運!

寫出 Clean Code 的一些技巧&原則

## 介紹 編寫乾淨的程式碼是每個軟體開發人員的基本技能。乾淨的程式碼不僅使您的程式碼庫更易於維護和理解,而且還能促進團隊成員之間的協作。在這篇綜合文章中,我們將探討什麼是乾淨的程式碼、為什麼它很重要,並為您提供一組最佳實踐和原則來幫助您編寫乾淨且可維護的程式碼。 - 原文出處:https://dev.to/favourmark05/writing-clean-code-best-practices-and-principles-3amh --- ## 什麼是乾淨程式碼? 乾淨的程式碼是易於閱讀、易於理解且易於修改的程式碼。它是沒有不必要的複雜性、冗餘和混亂的程式碼。乾淨的程式碼遵循一組約定和最佳實踐,使其更加一致,使多個開發人員更容易無縫地處理同一個專案。 ## 為什麼乾淨的程式碼很重要? 1. **可讀性**:乾淨的程式碼易於閱讀,這意味著任何人 - 包括未來的你 - 都可以快速理解它。這減少了掌握程式碼功能所需的時間,從而加快了開發和除錯速度。 2. **可維護性**:程式碼的讀取次數多於編寫次數。當您編寫乾淨的程式碼時,隨著時間的推移,維護和擴展應用程式將變得更加容易。這在軟體開發生命週期中至關重要,因為專案經常發展和成長。 3. **協作**:簡潔的程式碼鼓勵協作。當您的程式碼乾淨且組織良好時,其他團隊成員就可以有效地處理它。這使得劃分任務和同時處理程式碼庫的不同部分變得更容易。 4. **減少錯誤**:乾淨的程式碼可以減少引入錯誤的可能性。難以理解的程式碼在修改或增強過程中更容易出錯。 5. **效率**:乾淨的程式碼就是高效率的程式碼。它通常執行速度更快並且使用更少的資源,因為它避免了不必要的操作和複雜性。 現在我們了解了為什麼乾淨的程式碼很重要,讓我們深入研究一些最佳實踐和原則來幫助您編寫乾淨的程式碼。 ## 編寫簡潔程式碼的最佳實踐和原則 1. **有意義的變數和函數名稱** 對變數、函數、類別和其他辨識碼使用描述性名稱。精心選擇的名稱可以傳達實體的目的,使程式碼更容易理解。避免使用單字母變數名或神秘的縮寫。 ``` # Bad variable name x = 5 # Good variable name total_score = 5 ``` 2. **保持函數和方法簡短** 函數和方法應該簡潔並專注於單一任務。單一職責原則(SRP)指出,一個函數應該要做一件事,並且把它做好。較短的函數更容易理解、測試和維護。如果函數變得太長或太複雜,請考慮將其分解為更小、更易於管理的函數。 ``` // Long and complex function function processUserData(user) { // Many lines of code... } // Refactored into smaller functions function validateUserInput(userInput) { // Validation logic... } function saveUserToDatabase(user) { // Database operation... } ``` 3. **評論和文件** 謹慎使用評論,當你使用評論時,要讓它們變得有意義。程式碼應該盡可能不言自明。文件(例如內嵌註解和自述文件)可協助其他開發人員了解程式碼的目的和用法。記錄複雜的演算法、重要的決策和公共 API。 ``` # Bad comment x = x + 1 # Increment x # Good comment # Calculate the total score by incrementing x total_score = x + 1 ``` 4. **一致的格式和縮排** 堅持一致的編碼風格和縮排。這使得程式碼庫看起來乾淨且有組織。大多數程式語言都有社群接受的編碼標準(例如,Python 的 PEP 8、JavaScript 的 eslint),您應該遵循。一致性也適用於命名約定、間距和程式碼結構。 ``` // Inconsistent formatting if(condition){ doSomething(); } else { doSomethingElse(); } // Consistent formatting if (condition) { doSomething(); } else { doSomethingElse(); } ``` 5. **DRY(不要重複)原則** 避免重複程式碼。重複的程式碼更難維護並增加不一致的風險。將通用功能提取到函數、方法或類別中以提高程式碼的可重複使用性。當您需要進行更改時,只需在一個地方進行即可。 假設您正在開發一個 JavaScript 應用程式來計算購物車中商品的總價。最初,您有兩個單獨的函數來計算每種商品類型的價格:一個用於計算一本書的價格,另一個用於計算筆記型電腦的價格。這是初始程式碼: ``` function calculateBookPrice(quantity, price) { return quantity * price; } function calculateLaptopPrice(quantity, price) { return quantity * price; } ``` 雖然這些函數有效,但它們違反了 DRY 原則,因為計算總價的邏輯對於不同的商品類型是重複的。如果您有更多的專案類型需要計算,您最終將重複此邏輯。為了遵循DRY原則,提高程式碼的可維護性,可以對程式碼進行如下重構: ``` function calculateItemPrice(quantity, price) { return quantity * price; } const bookQuantity = 3; const bookPrice = 25; const laptopQuantity = 2; const laptopPrice = 800; const bookTotalPrice = calculateItemPrice(bookQuantity, bookPrice); const laptopTotalPrice = calculateItemPrice(laptopQuantity, laptopPrice); ``` 在此重構的程式碼中,我們有一個calculateItemPrice函數,它根據作為參數提供的數量和價格計算任何商品類型的總價。這遵循了 DRY 原則,因為計算邏輯不再重複。 現在,您可以通過使用適當的數量和價格值呼叫calculateItemPrice來輕鬆計算書籍、筆記本電腦或任何其他商品類型的總價。這種方法提高了程式碼的可重用性、可讀性和可維護性,同時降低了重複程式碼引起的錯誤風險。 6. **使用有意義的空白** 使用空格和換行符正確設置程式碼格式。這增強了可讀性。使用空格來分隔程式碼的邏輯部分。格式良好的程式碼更容易瀏覽,減少讀者的認知負擔。 ``` // Poor use of whitespace const sum=function(a,b){return a+b;} // Improved use of whitespace const sum = function (a, b) { return a + b; } ``` 7. **錯誤處理** 優雅地處理錯誤。在程式碼中使用適當的 try-catch 塊或錯誤處理機制。這可以防止意外崩潰並為除錯提供有價值的訊息。不要抑制錯誤或在沒有正確響應的情況下簡單地記錄錯誤。 ``` // Inadequate error handling try { result = divide(x, y); } catch (error) { console.error("An error occurred"); } // Proper error handling try { result = divide(x, y); } catch (error) { if (error instanceof ZeroDivisionError) { console.error("Division by zero error:", error.message); } else if (error instanceof ValueError) { console.error("Invalid input:", error.message); } else { console.error("An unexpected error occurred:", error.message); } } ``` 8. **測試** 編寫單元測試來驗證程式碼的正確性。測試驅動開發 (TDD) 可以迫使您預先考慮邊緣情況和預期行為,從而幫助您編寫更清晰的程式碼。經過良好測試的程式碼更加可靠並且更容易重構。 ``` // Example using JavaScript and the Jest testing framework test('addition works correctly', () => { expect(add(2, 3)).toBe(5); expect(add(-1, 1)).toBe(0); expect(add(0, 0)).toBe(0); }); ``` 9. **重構** 定期重構你的程式碼。隨著需求的變化以及您對問題域的理解的加深,請相應地調整您的程式碼。隨著專案的發展,重構有助於保持乾淨的程式碼。必要時不要害怕重新存取和改進現有程式碼。 假設您有一個函數,可以計算購物車中具有固定折扣百分比的商品的總價: ``` function calculateTotalPrice(cartItems) { let totalPrice = 0; for (const item of cartItems) { totalPrice += item.price; } return totalPrice - (totalPrice * 0.1); // Apply a 10% discount } ``` 最初,此函數計算總價並應用 10% 的固定折扣。然而,隨著專案的發展,您意識到您需要支持可變折扣。為了重構程式碼使其更加靈活,可以引入折扣參數: ``` function calculateTotalPrice(cartItems, discountPercentage) { if (discountPercentage < 0 || discountPercentage > 100) { throw new Error("Discount percentage must be between 0 and 100."); } let totalPrice = 0; for (const item of cartItems) { totalPrice += item.price; } const discountAmount = (totalPrice * discountPercentage) / 100; return totalPrice - discountAmount; } ``` 在這段重構的程式碼中: * 我們在calculateTotalPrice函數中新增了discountPercentage參數,讓您在呼叫函數時指定折扣百分比。 * 我們對discountPercentage 參數進行驗證,以確保其落在有效範圍內(0 到100%)。如果不在範圍內,我們會拋出錯誤。 * 折扣計算現在基於提供的discountPercentage,使功能更加靈活,能夠適應不斷變化的需求。 通過這種方式重構程式碼,你提高了它的靈活性和可維護性。您可以輕鬆地調整該函數來處理不同的折扣場景,而無需重寫整個邏輯。這證明了隨著專案的發展和需求的變化定期進行程式碼重構的重要性。 10. **版本控制** 使用 Git 等版本控制系統來跟踪程式碼更改。這使您可以與團隊成員有效協作,在必要時恢復到以前的版本,並維護專案開發的清晰歷史記錄。 Git 提供了程式碼審查、分支和合併工具,促進協作和程式碼整潔。 ##結論 編寫乾淨的程式碼不僅僅是一套規則,更是一種心態和紀律。它是關於建立易於閱讀、維護和擴展的軟體。通過遵循這些最佳實踐和原則,您可以成為一名更熟練的開發人員,生成高質量的程式碼。投入時間仔細檢查其他工程師的程式碼庫,特別是在開源專案中,可能是一種啟發性的體驗。通過這種探索,您將獲得對不同編碼風格和策略的寶貴見解。這種接觸使您能夠提煉出編寫原始、可持續程式碼庫的精髓。請記住,乾淨的程式碼是一個持續的旅程,通過練習,它會成為第二天性,從而實現更高效、更愉快的軟體開發。

Rust 新手文章:記憶體管理機制簡介

您是否想過當您**執行 Rust 程式**時**RAM**會發生什麼情況**?您編寫程式碼的**方式會如何干擾系統中的許多其他事物? 這篇文章將幫助您了解更多關於 *管理記憶體* 和 **RUST 如何運作** 的資訊。 原文出處:https://dev.to/canhassi/how-rust-memory-management-work-to-beginners-622 ## 1. Stack and Heap 在了解 rust 的作用之前,您必須先了解一些概念。一般來說,我們有兩種類型的內存,稱為:**堆疊和堆**。現在我們來介紹一下他們。 ### 1.1 記憶體:Stack 堆疊,顧名思義,**工作原理就像堆疊**,遵循**“後進先出”(LIFO)的原則。**也許分步驟解釋會更容易: *想像一下**一堆盤子**; *您放入的**第一道菜**是**最後取出的**; * 當**函數被呼叫**時,一塊記憶體被**「堆疊」在棧頂; * 當**函數結束**時,該區塊**“unstacked”**,釋放該記憶體。 通常,**編譯器**(在編譯時)知道將儲存在堆疊上的**值**,因為它知道需要儲存多少記憶體。此過程**自動**發生,所有值都會從記憶體中刪除。 下面是一個例子: ``` fn main() { let number = 12; // at this moment the variable has created println!("{}", number); // 12 } // When the owner (main function) goes out of scope, the value will be dropped ``` 在 Rust 中,我們只需使用「{}」即可建立一些作用域,這會在堆疊中加入具有有限生命週期的層。當您離開該特定*範圍*後,記憶體將被清除,您將遺失相關資訊。一個很好且簡單的例子是: ``` fn main() { { let number = 12; println!("{}", number); // 12 } println!("{}", number); // Cannot find value `number` in this scope } ``` ### 1.2 記憶體:Heap 簡而言之:**堆**記憶體是一個空閒記憶體空間,用於分配可能更改的資料。 想像一下,您需要在啟動程式後**儲存一些變數**,該變數在編譯時沒有已知的固定大小,因為它可能有大小變化或是記憶體中的直接分配。 如果上述可能性之一匹配,我們就知道我們有 **堆** 內存,而不是 **堆疊**。堆擁有更**靈活的記憶體**和更大的空間。看一看: ``` let number = Box::new(12); // alocate a integer in heap let name = String::from("Canhassi"); // alocate a String in heap ``` 在 Rust 中,我們有兩種字串「類型」:「&str」和「String」。 * **&str**:根據所寫的文字有固定的大小; * **字串**:具有可以增加、減少和刪除的大小。 ……這就是為什麼 `String` 儲存在堆上,而 `&str` 儲存在堆疊上。 釋放堆記憶體的一種方法是:當儲存堆上某些內容的**變數離開函數的作用域(到達函數末端)時,它將以相同的方式釋放作為堆疊。 好了,現在我們對這兩種記憶體類型有了一個清晰的認識,但是堆疊和堆在管理記憶體方面有什麼區別呢?讓我們看看這些差異吧! ## 2. 借用檢查器 借用檢查器是 Rust 編譯器的**部分**,它**檢查並確保**所有權、借用和生命週期**規則得到尊重**。 老實說:一開始我在理解它是如何運作的方面遇到了一些問題,我發現這在新的 Rustaceans 中很常見。但別擔心,我的朋友。我會用最好的方式教你。但首先,讓我們先來看看下面的程式碼: ``` fn main() { let name = String::from("Canhassi"); // Creating a string variable print_name(name); // calling the print_name function passing the variable println!("{}", name); // Error: name borrowed to print_name() } fn print_name(name: String) { println!("{}", name); // print "Canhassi" } ``` 如果您使用該程式碼執行編譯器,您將看到以下錯誤: ``` borrow of moved value: name ``` 當我們呼叫“print_name”函數時,“name”變數將被**移動到另一個作用域**,並且該作用域將成為它的**新所有者**。並且所有者的規則超出範圍將再次應用。借用檢查器確保**一旦所有權轉移**,原始變數**不能再用於**來存取該值。這發生在上面的程式碼中。 使用原始變數的另一種方法是使用類似的引用。 ``` fn main() { let name = String::from("Canhassi"); // Creating a string variable print_name(&name); // calling the print_name function passing the variable println!("{}", name); // print "Canhassi" } fn print_name(name: &String) { println!("{}", name); // print "Canhassi" } ``` PS:這些**借用檢查器的規則僅適用於**堆中指派的物件**。 ## 3. 錯誤預防 借用檢查器對於確保 Rust 記憶體安全而無需[垃圾收集器](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)) 至關重要。 在 C 和 C++ 等其他語言中,我們(作為開發人員)必須使用某些函數手動釋放記憶體。 C++ 以允許記憶體管理錯誤而聞名,包括[記憶體洩漏](https://en.wikipedia.org/wiki/Memory_leak)。 C++本身不會導致記憶體洩漏。相反,**C++ 為程式設計師提供了大量的靈活性**和控制力,如果使用不當,這種**自由可能會導致錯誤**。 一個著名的錯誤是**未定義的行為**,例如,想像一個函數傳回這樣的變數的引用 ``` fn main() { let number = foo(); // calling foo function } fn foo() -> &i32 { let number = 12; // creating a var number &number // try return a reference of var number } ``` 程式碼不起作用,因為 Rust 編譯器對記憶體管理有限制規則。我們不能回傳 var `number` 的引用,因為這個函數的作用域將會消失,而 var `number` 將會消失,所以 Rust 不會讓這種情況發生。在 C++ 中我們可以做到這一點,並且它允許臭名昭著的記憶體洩漏。 我認為知道 Rust 編譯器避免了這種類型的錯誤真是太酷了...如果這個主題對您來說是新的,我可以說內存洩漏可能會花費很多錢並且確實很難修復它,因為絕不只有一次內存洩漏。 其他範例是,**雙重釋放**,當您嘗試釋放相同物件兩次(例如在 C 程式碼中)時,就會發生這種情況。 ``` char* ptr = malloc(sizeof(char)); *ptr = 'a'; free(ptr); free(ptr); ``` 這個主題非常廣泛,當您使用其他語言時,很可能會產生類似的錯誤。但是,我會讓您自己進行研究,並確保在這篇文章的評論中告訴我更多! ## 4。結論 我寫這篇文章的目的是以更一般的方式展示記憶體管理如何與 Rust 配合使用。但我建議您閱讀《Rust 程式語言》一書的第 4 章( https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html )來獲得更完整的知識。在那裡您將獲得更多示例和更多關於此內容的解釋。 希望這篇文章有幫助! 🦀🦀

回答網友提問:40歲外商高薪工程師,有點想降薪去新創公司試試看,怎麼辦?

阿川收到網友提問如下: ``` 站長阿川您好 我是一名App工程師 從2013年第一份工作到現在近10年 這十年我從工程師到資深工程師到管理職位都有相關經驗 一共經歷四份工作 離開公司原因大多是與人理念不合 今年邁入40歲 目前在一間外商工作 年薪約200左右 最近又再找尋新機會 但是相關職位看到我的經歷常常被拒絕 因為該職位不想要這麼資深的 不然就是年薪必須砍半 最近有一個機會可以加入幾個創業家所組成的公司 缺點是薪資可能只剩下現有的1/3 優點是可以接觸相關人士學到創業可能所需的技能 也可以藉由這樣機會建立屬於自己的產品一步步養活自己 在網路上看到您的文章彷彿醍醐灌頂 也對於長年職涯生命握在別人手上感到非常不適應 但是我明白產品可能不是自身想像那麼容易打造 不過我仍想試試看 不知道您這邊是否有什麼想法可以對我未來要走的路提供一些建議 非常感謝您撥空看完 ``` 這主題很好,我決定單獨寫一篇文章討論這件事情,跟大家分享一下 --- 首先,這位朋友目前的工作狀況,外商、200萬年薪,如果工作壓力不大、下班時間正常,辦公室氣氛融洽 這麼好的條件,如果放棄這份工作,實在相當可惜! 有沒有考慮利用下班&週末的時間,寫一些自己的作品、app,試試看? 一人獨立開發,或者找朋友一起經營,都可以,做完之後,到相關的 FB 社團、批踢踢看板,宣傳一下 會學到很多商業、經營、行銷的技能,會很好玩 也或許,你會發現要做的事情太多、太雜、太難,你會滿不適應的,那樣的話,你會重新看見現職公司的美好 --- 再來,如果目前的公司實在很煩,除了高薪之外,工時、工作內容、環境壓力,你根本通通都不喜歡、鐵了心想要離職 那麼眼前的選項就是 - 找類似工作,薪水變二分之一 - 前往新創嘗試,薪水變三分之一 這樣的話,我有一個小原則跟你分享 # 職涯判斷技巧:Ctrl+Z 不心痛原則 這是我發明給自己,在面臨重大決定會用的一個原則 Ctrl+Z 是工程師每天會用到的快捷鍵:「恢復上一動」 在面臨選項的時候,可以去想想:「恢復上一動」的成本會很高嗎? ### 「我該先做哪一個決定,到時反悔的話,可以 Ctrl+Z 不心痛呢?」 舉例來說,社會新鮮人有點想考公務員 vs 想去業界上班看看 如果先考公務員,工作之後迷惘,想辭職去業界,這時「Ctrl+Z」的成本就非常高,因為當初花了數個月準備國考 如果先去業界上班,工作之後迷惘,想去考公務員,這時「Ctrl+Z」的成本就低很多,因為當初就是花一些時間面試而已 所以迷惘的社會新鮮人,我都是建議先去業界面試看看,再去考公務員 --- 再舉一個例子,年輕工程師想去大公司面試 vs 想去新創面試 大公司面試流程很多、面試成本很高,去新創通常聊一個下午就錄取了 所以迷惘的年輕工程師,我都是建議先去新創工作看看,如果之後再去大公司上班,心態就會很穩,因為你知道新創時髦的外表底下,其實愚蠢的地方也不少,你會比別人更看見大公司的美好 如果到了大公司才嚮往新創,到時再次反悔、重新面試大公司的成本就高很多、這樣很浪費時間 --- 我認為現代人,不管做什麼選擇,一定都會覺得迷惘、好奇當初沒做的那個選擇、常常會有遺憾 所以重點不是「如何第一次就做出正確決定」,因為做不到 重點是「**我該先做哪一個決定,到時反悔的話,可以 Ctrl+Z 不心痛呢?**」 這種路徑,比較不留遺憾,因為各種路都走過了,並且算是一種逐漸認識自己的過程 這樣做決定,會容易許多吧!我自己都是這樣做的~ --- 以這位網友面臨的狀況: - 降薪50%去類似環境的大公司上班,然後繼續迷惘新創公司是什麼樣子 - 降薪66%去新創公司看看,然後可能很喜歡、也可能發現是在浪費時間 如果選後者,去工作半年一年,真的不喜歡,頂多就是回去找大公司面試,這樣「Ctrl+Z」的成本也不高吧? 我會覺得就去新創看看也沒關係,因為之後反悔的成本也沒多高,而且這種事就是體驗過才知道 # 結論 其實創新、創業,極度困難、要做的事情也很雜亂 在我跟各種新創公司合作的經驗來說,很多時候其實也是浪費時間、有點像在幫老闆圓個人夢想,產品本身很爛。當然我也跟很多優秀新創合作過、學到很多寶貴技能 總之去新創不一定好玩,也不一定學得到東西 但我認為有策略性地、管理好各種職涯選擇的成本、在過程中認識自己、增廣見聞、降低迷惘,是很重要的 這位網友如果本身有房貸、車貸、家庭孩子要養,那麼這個抉擇確實非常困難 另一方面,職業生涯不是只有充實金錢&地位,能夠充實人生經驗&體驗,也是很有意義的,不是嗎? 建議靜下心,好好的幫自己分析一下、聽聽看內心的聲音,新選項真的讓你有「義無反顧」的感覺嗎? --- 我另外還有一些幫助工程師觀察「眼前這位迷人的創業者,有沒有可能是個地雷」的技巧,有機會再跟大家分享吧~! 以上,簡單幾點分享,希望對大家有幫助,祝各位都有滿意、幸福的職業生涯!

回答網友提問:新手去上班,該選接案公司好?還是自有產品的公司好?

昨天在我們新手寫程式 LINE 群組,有幾個工程師&想轉職的新手在討論: > 各位前輩們好,小弟是自學轉職的前端工程師,目前有兩個 offer,一個是接案公司;一個是自有產品,自有產品的那間目前只有一個junior前端,進去有問題可能沒人可以問,但看網路上好像都不太推接案公司。猶豫了很久選不出來想聽聽各位前輩的看法。 https://line.me/ti/g2/nipkjq2WoZPKX5dTn9tE9266aEOt6EOICFGa1g 這主題很好,我決定單獨寫一篇文章討論這件事情,跟大家分享 --- 阿川幫大家從幾個角度來分析比較一下 # 學習的深度、廣度 接案公司通常是使用類似的技術,接不同的客戶專案 好處是可以接觸很多不同的客戶,認識許多不同產業 壞處是做久了可能會開始有「重複感」,也就是好像一直在做類似的事情,有點學不到東西 產品公司通常是長期深入研發自家產品、技術 所以會在同一領域鑽研,通常可以玩得比較深入、學得比較深入 壞處是可能長期只能使用同一技術、框架,沒機會玩別款的 接案公司有時需要面對不同技術需求的客戶,有機會玩玩不同款的語言、框架、技術 # 工作的時程壓力 接案公司的時程壓力來自於「客戶」,通常已經由老闆、PM 跟對方承諾某個時間,甚至已經寫在合約上 如果同時在開發多個專案的話,有時候工程師會感到相當的壓力 通常是忙一陣、閒一陣這樣 產品公司沒有這樣的壓力,壓力通常來自於「公司沒有在賺錢」 如果公司經營穩定、產品前景看好、主管有肩膀好說話 那像這樣的時程壓力,通常會小很多 # 技術債 稍微資深的工程師,在不同公司面試時,一定會問的問題是:入職之後,需要維護 legacy(老舊)專案嗎? 維護老舊專案、負擔技術債,是一件很悲慘的事情,也是開發者的主要離職原因之一 你會被迫用已經過時的工具、語法在開發,並且要把設計拙劣的系統架構「硬搬進自己腦子裡」才能消化開發 這過程能學到東西嗎?我認為不多,基本上是在糟蹋生命 接案公司來說,如果主要負責一些新客戶,那麼經常在重啟新專案,技術債問題或許不大 如果手上負責很多「超舊的專案與客戶」,那麼可能會遇到技術債的問題 自有產品的公司,則是走向另一個極端 如果是持續有在更新版本、升級套件的熱情公司,那麼技術債問題不大 如果是有年紀、穩定的系統,那麼版本問題、系統架構的技術債問題,可能很大 嚴重起來會比接案公司更慘,因為就只有一個專案在跑 # 進去有問題可能沒人可以問 大家都希望團隊能有一個又強、人又好、又願意幫忙自己的好同事 不過這可遇不可求,身為正職工程師,你需要能夠獨立解決問題 畢竟人家也面試過了,應該就是合格了,如果真的丟一些無法解決的問題給你,那也不全是你的錯 另一方面,沒人可以問,代表你獨立做決定的空間很大,這未必是壞事 # 結論 剛轉職的新手上班,我是覺得去接案公司上班也可以 通常接案公司很缺人,也比較願意給半路出家者機會 而且開始工作的前 1-2 年,不管去什麼公司,通常都能學到很多東西 待了 2-3 年之後,覺得無聊了,再找新工作也不遲 所以回到原 po 的問題:我認為兩間公司都可以,沒有說接案公司一定比較不好 畢竟,就算是自有產品的公司,如果產品本身超爛,根本永遠不會賺錢、沒人想用 那就只是一大群人在「陪老闆追逐他的個人夢想」,那其實也是相當浪費時間的,不如在接案公司專心滿足客戶,比較充實 --- 我建議閣下不妨從「人和」的角度來觀察一下:你喜歡面試時看到的那些人嗎? 老闆、主管、同事,你喜歡跟他們相處嗎?還是你有點畏懼他們、覺得他們有點冷漠、城府、可怕? 如果實在不知怎麼選,就選你喜歡的那群人吧!跟合得來的人一起工作,總是不會太不舒服! 以上,簡單分享,給各位參考!也歡迎大家多多在留言區補充經驗、意見!

改善重用性:Vue Composables 的推薦技巧&Design Patterns

本文將分為三個部分: 1. 通用設計模式 2. 我的建議 3. 進一步閱讀 享受並且讓我知道您在專案中使用的模式和實踐🚀 原文出處:https://dev.to/jacobandrewsky/good-practices-and-design-patterns-for-vue-composables-24lk ## 通用設計模式 我認為了解建置可組合項模式的最佳來源實際上是 Vue.js 文件,您可以在[此處](https://vuejs.org/guide/reusability/composables.html)查看 ### 基本可組合項 Vue 文件顯示了以下 useMouse 可組合項的示例: ``` // mouse.js import { ref, onMounted, onUnmounted } from 'vue' // by convention, composable function names start with "use" export function useMouse() { // state encapsulated and managed by the composable const x = ref(0) const y = ref(0) // a composable can update its managed state over time. function update(event) { x.value = event.pageX y.value = event.pageY } // a composable can also hook into its owner component's // lifecycle to setup and teardown side effects. onMounted(() => window.addEventListener('mousemove', update)) onUnmounted(() => window.removeEventListener('mousemove', update)) // expose managed state as return value return { x, y } } ``` 稍後可以在元件中使用它,如下所示: ``` <script setup> import { useMouse } from './mouse.js' const { x, y } = useMouse() </script> <template>Mouse position is at: {{ x }}, {{ y }}</template> ``` ### 異步可組合項 為了獲取資料,Vue 建議使用以下可組合結構: ``` import { ref, watchEffect, toValue } from 'vue' export function useFetch(url) { const data = ref(null) const error = ref(null) watchEffect(() => { // reset state before fetching.. data.value = null error.value = null // toValue() unwraps potential refs or getters fetch(toValue(url)) .then((res) => res.json()) .then((json) => (data.value = json)) .catch((err) => (error.value = err)) }) return { data, error } } ``` 然後可以在元件中使用它,如下所示: ``` <script setup> import { useFetch } from './fetch.js' const { data, error } = useFetch('...') </script> ``` ### 可組合合約 根據上面的示例,以下是所有可組合項都應遵循的約定: 1. 可組合文件名應以 use 開頭,例如 `useSomeAmazingFeature.ts` 2. 它可以接受輸入參數,這些參數可以是字串等基本類型,也可以接受 refs 和 getter,但需要使用 toValue 幫助器 3. Composable 應該返回一個 ref 值,該值可以在解構可組合項後存取,例如 `const { x, y } = useMouse()` 4. 可組合項可以保存可以在整個應用程式中存取和修改的全局狀態。 5. 可組合性可能會產生副作用,例如加入窗口事件偵聽器,但在卸載元件時應清除它們。 6. 可組合項只能在 `<script setup>` 或 `setup()` 掛鉤中呼叫。它們也應該在這些上下文中同步呼叫。在某些情況下,您還可以在生命週期掛鉤中呼叫它們,例如“onMounted()”。 7. 可組合項可以呼叫內部的其他可組合項。 8. 可組合項應在內部包裝某些邏輯,當過於復雜時,應將它們提取到單獨的可組合項中以便於測試。 ## 我的建議 我已經為我的工作專案和開源專案建置了多個可組合項 - NuxtAlgolia、NuxtCloudinary、NuxtMedusa,因此基於這些,我想根據我的經驗在上面的合同中加入一些要點。 ### 有狀態或/和純函數可組合項 在程式碼標準化的某個時刻,您可能會得出這樣的結論:您希望對可組合項中的狀態保留做出決定。 最容易測試的函數是那些不存儲任何狀態的函數(即它們是簡單的輸入/輸出函數),例如負責將字節轉換為人類可讀值的可組合函數。它接受一個值並返回一個不同的值 - 它不存儲任何狀態。 不要誤會我的意思,你不必做出“或”的決定。您可以完全保留有狀態和無狀態可組合項。但這應該是一個書面決定,以便以後更容易與他們合作 🙂 ### 可組合項的單元測試 我們希望使用 Vitest 為我們的前端應用程式實施單元測試。在後端工作時,進行單元測試程式碼覆蓋率非常有用,因為您主要關注邏輯。然而,在前端,您通常使用視覺效果。 因此,我們認為對整個元件進行單元測試可能不是最好的主意,因為我們基本上將對框架本身進行單元測試(如果按下按鈕,檢查狀態是否更改或模式是否打開)。 由於我們已將所有業務邏輯移至可組合項(基本上是 TypeScript 函數)內,因此它們很容易使用 Vitest 進行測試,並且允許我們擁有更穩定的系統。 ### 可組合項的範圍 不久前,在 VueStorefront 中,我們開發了自己的可組合方法(早在它們實際上像這樣被呼叫之前)。在我們的方法中,我們使用可組合項來映射電子商務的業務領域,如下所示: ``` const { cart, load, addItem, removeItem, remove, ... } = useCart() ``` 這種方法絕對有用,因為它允許將域包裝在一個函數中。在“useProduct”或“useCategory”等更簡單的示例中,實現和維護相對簡單。然而,正如您在此處的“useCart”示例中看到的那樣,當包裝一個包含更多邏輯而不僅僅是資料獲取的域時,這個可組合項正在發展成為一種非常難以開發和維護的形狀。 此時,我開始為 Nuxt 生態系統做出貢獻,其中引入了不同的方法。在這種新方法中,每個可組合項僅負責一件事。因此,我們的想法不是建置一個巨大的“useCart”可組合項,而是為每個功能建置可組合項,即“useAddToCart”、“useFetchCart”、“useRemovefromCart”等。 因此,維護和測試這些可組合項應該更容易 🙂 ## 進一步閱讀 這將是我的研究的全部內容。如果您想了解有關此主題的更多訊息,請務必查看以下文章: * https://vuejs.org/guide/reusability/composables.html * https://www.youtube.com/watch?v=bcZM3EogPJE * https://vueschool.io/articles/vuejs-tutorials/what-is-a-vue-js-composable/ * https://blog.logrocket.com/getting-started-vue-composables/ * https://macopedia.com/blog/news/how-can-vue-3-composables-make-your-life-easier

在 React 裡面,關於 Strict Mode 的簡單說明

`React.StrictMode` 是一個好用的元件,用於突出顯示應用程式中的潛在問題。就像 `<Fragment>` 一樣,`<StrictMode>` 不會渲染任何額外的 DOM 元素。在這篇文章中,我們將深入探討什麼是嚴格模式、它是如何運作的,以及為什麼你應該考慮使用看看。 原文出處:https://dev.to/codeofrelevancy/what-is-strict-mode-in-react-3p5b --- ## 什麼是 React 中的嚴格模式? 嚴格模式是一組開發工具,可幫助您在程式碼中找到潛在問題。當您在 React 應用程式中啟用嚴格模式時,您實際上是在告訴 React 打開一堆額外的檢查👀 和警告,以便幫助您寫出更好的程式碼。這些檢查和警告可以捕獲以下內容: 1. 有副作用的元件 2. 已棄用或不安全的生命週期方法 3. 某些內置函數的不安全用法 4. 列表中的重複鍵 ![嚴格模式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/10tfwojwoyip5ld20yec.gif) --- ## 啟用嚴格模式 在 React 應用程式中啟用嚴格模式非常簡單。您可以通過在主 `index.js` 文件中加入一行程式碼來實現: ``` import React from 'react'; import ReactDOM from 'react-dom'; ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); ``` ## 為應用程式的一部分啟用嚴格模式 您還可以為應用程式的任何部分啟用嚴格模式: ``` import { StrictMode } from 'react'; function App() { return ( <> <Header /> <StrictMode> <main> <Sidebar /> <Content /> </main> </StrictMode> <Footer /> </> ); } ``` 在這種情況下,嚴格模式檢查不會針對“頁首”和“頁腳”元件執行。但是,它們將在 `Sidebar` 和 `Content` 以及它們內部的所有元件上執行,無論它有多深層。 --- ## 嚴格模式只影響開發環境 請務必注意,嚴格模式對 React 應用程式的正式環境建置沒有影響。嚴格模式啟用的任何檢查或警告都不會出現在用戶看到的應用程式最終版本中。除此之外,嚴格模式會打開額外的檢查和警告,它可能會減慢您的開發環境速度。 ![嚴格模式只影響開發環境](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nu5kpm4ixxfesjdhv1cv.gif) --- ## 嚴格模式可以幫助你捕捉細微的錯誤 有時 React 應用程式中的錯誤可能很難追踪,特別是諸如 race conditions 或對元件狀態的不正確假設等細微問題。啟用嚴格模式的額外檢查和警告,您可以在這些錯誤導致嚴重問題之前發現它們。 --- ## 嚴格模式可以幫助您了解最新的最佳實踐 React 是一個快速發展的框架,最佳實踐會隨著時間而改變。啟用嚴格模式並留意它提供的警告和建議,您可以確保您的 React 程式碼遵循當前的最佳實踐。例如在渲染列表時使用 key 屬性,或者在 render() 中避免副作用。 --- ## 儘早發現潛在問題 嚴格模式可以在您的程式碼中發現可能在未來引起的問題,以免它們成為嚴重問題。比方說,它可以檢測並警告已棄用的生命週期方法以及對不再推薦的 [findDOMNode()](https://react.dev/reference/react-dom/findDOMNode) 的存取。 ![findDOMNode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/awx9dnh9eexg4eb73wt2.png) ![findDOMNode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5hjs6oae3lj38mbhjwk.png) --- ## 防止常見錯誤 啟用嚴格模式,您可以避免一些隱晦的常見錯誤,例如:直接修改狀態而不是使用 setState()、使用未宣告變數。 --- ## 辨識不安全的生命週期 React Strict Mode 可以幫助辨識元件中不安全生命週期方法的使用。例如,它可以警告您使用 `componentWillUpdate` 和 `componentWillReceiveProps` 方法,這兩種方法都被認為是不安全的,將在 React 的未來版本中被刪除。 ![不安全生命週期](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6d9qh4xjz16u9xlsle5.png) 假設您有一個元件,它使用 `componentWillReceiveProps()` 來根據傳入的 props 更新其狀態: ``` class BlackMamba extends React.Component { constructor(props) { super(props); this.state = { venom: props.venom }; } componentWillReceiveProps(nextProps) { this.setState({ venom: nextProps.venom }); } render() { return <div>{this.state.venom}</div>; } } ``` 在常規模式下,該元件會按預期工作,但在“React.StrictMode”下,您會在控制台中看到一條警告: > 警告:BlackMamba 使用 `componentWillReceiveProps`,這被認為是一種不安全的生命週期方法。請使用靜態的 getDerivedStateFromProps 。 --- ## 過時的字串引用 API 用法 嚴格模式還可以警告您過時的字串 `ref` API 的使用。該 API 已被官方棄用。您應該使用更安全、更易於使用的 `createRef` API。 ![過時的字串引用 API 用法](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gv8lf8ubk7vv4yg8m4qo.png) 比方說,您有一個元件使用這樣的字串引用: ``` import { Component } from "react"; import { createRoot } from "react-dom/client"; class BlackMamba extends Component { componentDidMount() { this.refs.venom.focus(); } render() { return ( <> <h1>Black Mamba</h1> <input ref="venom" /> </> ); } } const root = createRoot(document.getElementById("root")); root.render(<BlackMamba />); ``` 您不會在控制台中看到任何錯誤。 ![輸出](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/trxw9auusgunit73rvzp.png) 當您像這樣在您的應用中啟用“React.StrictMode”時: ``` import { StrictMode, Component } from "react"; import { createRoot } from "react-dom/client"; class BlackMamba extends Component { componentDidMount() { this.refs.venom.focus(); } render() { return ( <> <h1>Black Mamba</h1> <input ref="venom" /> </> ); } } const root = createRoot(document.getElementById("root")); root.render( <StrictMode> <BlackMamba /> </StrictMode> ); ``` 您會在控制台中看到如下所示的警告: > Warning: A string ref, "venom", has been found within a strict mode tree. String refs are a source of potential bugs and should be avoided. We recommend using useRef() or createRef() instead. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref ![輸出](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tnf0qdctk8q7q9d1mzf0.png) 讓我們用 `createRef` API 修復它: ``` import { StrictMode, Component, createRef } from "react"; import { createRoot } from "react-dom/client"; class BlackMamba extends Component { constructor(props) { super(props); this.venom = createRef(); } componentDidMount() { this.venom.current.focus(); } render() { return ( <> <h1>Black Mamba</h1> <input ref={this.venom} /> </> ); } } const root = createRoot(document.getElementById("root")); root.render( <StrictMode> <BlackMamba /> </StrictMode> ); ``` 修理完成! ![輸出](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0pq7w11m292b3sh9e3aj.png) --- ## 過時的 Context API [舊版 Context API](https://legacy.reactjs.org/docs/legacy-context.html) 在 React 中已棄用,已被新的 Context API 取代。 React Strict Mode 可以幫助您檢測過時的 Context API 的任何使用情況,並鼓勵您切換到 [新 API](https://react.dev/reference/react/useContext) ![檢測遺留上下文 API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iowjhzc795mngti4ayo0.png) --- 如果您還沒有使用嚴格模式,那絕對值得使用看看! 以上簡單分享,希望對您有幫助!

給新手參考:前端專案的檔案架構範例

在開發 Web 應用程式時建立可維護的檔案結構很重要,良好的架構有助於組織程式碼,並使其他開發人員了解您的 Web 應用程式結構。 原文出處:https://dev.to/noruwa/folder-structure-for-modern-web-applications-4d11 ### 設計檔案結構的一些技巧 - 了解您的 Web 專案的目的:為了弄清楚如何組織您的 Web 專案,您需要很好地了解專案需求 - 為您的文件夾和文件使用正確的命名慣例,它們應該描述您的 Web 應用程式的用途 ### 結構及說明 **Assets** assets 包含將在您的 Web 應用程式中使用的所有圖像、圖示、css 文件、字體文件等。自定義圖像、圖示、付費字體都放在這個文件夾中。 ![資產](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bosdpni04f4rhoscokrl.PNG) **Contexts** 當使用 React Js 作為您的前端 ui 庫時,context 文件夾存放所有跨元件和多個頁面使用的 react context 檔案。 ![上下文](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34ah8q7qbthfe5pbkcbf.PNG) **Components** components 文件夾包含應用程式的 UI。包含我們所有的 UI 元件,如導航列、頁腳、按鈕、視窗、卡片等等。 ![元件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0fsm5cd609kxc1ydcv4b.PNG) ** Composables** 在 Vue 應用程式中,“Composables”是一種利用 Vue 的組合 API 來封裝和重用有狀態邏輯的功能。 **Data** 用來放會在不同部分和頁面中作為 JSON 文件使用的文本資料。這樣做將使資訊更新更容易。 ![資料 JSON](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/74ey2c253fveerw4ox3y.PNG) ![資料](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mybd8n92pxns26feb6qt.PNG) **Features** 包含每個頁面(身份驗證、主題、視窗)會用到的功能。例如,每個頁面可能都會用到視窗功能。 ![功能](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gljjlh0jgarivzabdamm.PNG) **Hooks** 讓 React 元件有狀態和生命週期特性的函數。我們還可以建立名稱以“use”開頭的自定義掛鉤,並可用於呼叫其他掛鉤。 ![掛鉤](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a84dq8pahtjgff63ru7e.PNG) **Layouts** 在定義網頁的總體外觀時,Layouts 文件夾會派上用場。它用於放置佈局的元件,例如側邊欄、導航欄和頁腳。如果您的 Web 應用程式有很多佈局,這個文件夾是保存它們的好地方。 ![佈局](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6h73gy0uruci8qlq5sjl.PNG) **Modules** Modules 文件夾處理應用程式中的特定任務。 ![模塊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/boeni6zfudcg14201s87.PNG) **Pages** pages 目錄包含您的 Web 應用程式畫面。 Next Js 和 Nuxt Js 等前端框架中的頁面目錄,會讀取目錄中的所有文件並自動為您建立路由設定。 ** Public** 直接在伺服器根目錄提供服務,包含不會更改的公共文件,例如 favicon.ico。 **Routes** routes 文件夾只是你的 web 應用程式中的一個地方,用於存放到不同頁面的路由路徑。 ** Utility/Utils** 該文件夾用於存放所有實用函數,例如 auth、theme、handleApiError 等。 ** Views** Views 文件夾類似於 pages 文件夾,用來放頁面的重複部分。 ### 結論 良好的檔案結構可以讓您和其他開發人員更快地找到文件並更輕鬆地管理它們。希望這篇文章對您有幫助!

適用於各種軟體開發技能:2023 推薦練習的專案開發

作為一名開發人員,了解最新的技術和工具對於在就業市場上保持競爭力至關重要。 在這篇文章中,我們整理了一份 2023 年最熱門開發專案的完整列表,以及掌握每個專案的教程和資源。 無論您是希望提高技能的初學者,還是希望擴展您的技能組合的資深開發人員,此列表都適合每個人。 - 原文出處:https://dev.to/rahul3002/2023s-top-development-projects-for-programmers-a-complete-list-of-tutorials-and-tools-for-mastering-the-latest-technologies-37o3 --- ## 專案教程列表: ### Web開發: |專案 |技術 |連結 | | :--- |:---|:---| |使用 NextJS 建置 Reddit 2.0 克隆 | React、SQL、Supabase、Next.js、GraphQL | [連結](https://projectlearn.io/learn/web-development/project/build-reddit-2.0-clone-with-nextjs-205?from=github)| |使用 React 建置 YouTube 克隆 | Express、Node、JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/build-a-youtube-clone-with-react-200?from=github)| |使用 JavaScript 圖表庫建立發散條形圖 | JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/create-a-diverging-bar-chart-with-a-javascript-charting-library-197?from=github)| |通過建置卡片組件學習 CSS 基礎知識 | HTML, CSS | [連結](https://projectlearn.io/learn/web-development/project/learn-css-basics-by-building-a-card-component-196?from=github)| |建立無伺服器模因即服務 | JavaScript、Rust、CSS、HTML | [連結](https://projectlearn.io/learn/web-development/project/create-a-serverless-meme-as-a-service-194?from=github)| |天氣預報網站 | JavaScript、HTML、CSS、React | [連結](https://projectlearn.io/learn/web-development/project/weather-forecast-website-193?from=github)| |連結縮短網站 | JavaScript、Vue、HTML、CSS、React | [連結](https://projectlearn.io/learn/web-development/project/link-shortener-website-192?from=github)| |抄襲檢查器網站 | Python, 引導 | [連結](https://projectlearn.io/learn/web-development/project/plagiarism-checker-website-189?from=github)| |建置自定義 Google 地圖主題 | JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/build-a-custom-google-maps-theme-187?from=github)| |使用 JavaScript 建置超級馬里奧主題的 Google 地圖 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/build-a-super-mario-themed-google-map-with-javascript-180?from=github)| |建置社區驅動的交付應用程式 | Python、Django、PostgreSQL、JavaScript、Mapbox | [連結](https://projectlearn.io/learn/web-development/project/build-a-community-driven-delivery-application-176?from=github)| |建置本地商店搜尋和發現應用程式 | Python、Django、PostgreSQL、JavaScript、Mapbox | [連結](https://projectlearn.io/learn/web-development/project/build-a-local-store-search-and-discovery-application-175?from=github)| |使用 React.js 和 Node.js 的中型克隆 |React、Node、CSS3、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/medium-clone-using-react.js-and-node.js-174?from=github)| |使用 React JS 克隆 Facebook |React、Firebase、CSS3、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/facebook-clone-with-react-js-171?from=github)| | JavaScript30 - 30 天 Vanilla JS 編碼挑戰 | JavaScript | [連結](https://projectlearn.io/learn/web-development/project/javascript30---30-day-vanilla-js-coding-challenge-170?from=github)| |使用 Gatsby 和 GraphCMS 的旅行遺願清單地圖 |Gatsby、Leaflet、GraphCMS、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/travel-bucket-list-map-with-gatsby-and-graphcms-168?from=github)| |使用 Vue.js 的記憶卡遊戲 | Vue、JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/memory-card-game-with-vue.js-167?from=github)| | Strapi 和 GatsbyJS 課程 - 投資組合專案 | Strapi、Gatsby、JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/strapi-and-gatsbyjs-course---portfolio-project-166?from=github)| | Storybook - Node、Express、MongoDB 和 Google OAuth | MongoDB、Node、JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/storybook---node,-express,-mongodb-and-google-oauth-165?from=github)| |呼吸和放鬆應用程式 - JavaScript 和 CSS 動畫 | JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/breathe-and-relax-app---javascript-and-css-animations-164?from=github)| |用於加密貨幣價格的 Node.js CLI |Node,JavaScript | [連結](https://projectlearn.io/learn/web-development/project/node.js-cli-for-cryptocurrency-prices-163?from=github)| | React 和 Tailwind CSS 圖片庫 |React,順風,JavaScript,HTML,CSS | [連結](https://projectlearn.io/learn/web-development/project/react-and-tailwind-css-image-gallery-162?from=github)| |使用 React 的番茄鐘 |React,JavaScript,HTML,CSS | [連結](https://projectlearn.io/learn/web-development/project/pomodoro-clock-using-react-161?from=github)| | Laravel 從零開始的關鍵字密度工具 | Laravel、PHP、JQuery、AJAX、SEO | [連結](https://projectlearn.io/learn/web-development/project/keyword-density-tool-with-laravel-from-scratch-160?from=github)| |使用 Yii2 PHP 框架克隆 YouTube | Yii2, PHP | [連結](https://projectlearn.io/learn/web-development/project/youtube-clone-using-yii2-php-framework-159?from=github)| |使用 React、GraphQL 和 Amplify 克隆 Reddit | React、Amplify、AWS、GraphQL、Node | [連結](https://projectlearn.io/learn/web-development/project/reddit-clone-with-react,-graphql-and-amplify-157?from=github)| |使用 React 和 GraphQL 的全棧 Yelp 克隆 |React、GraphQL、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/full-stack-yelp-clone-with-react-and-graphql-155?from=github)| |帶有 React Hooks 和 Context API 的 Pokémon Web App |React、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/pokémon-web-app-with-react-hooks-and-context-api-154?from=github)| |使用 JavaScript 和 Rails 進行分水嶺監控 | Ruby、Rails、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/watershed-monitor-using-javascript-and-rails-153?from=github)| |使用 React 和 Redux 的氣候資料儀表板 | React、Redux、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/climate-data-dashboard-using-react-and-redux-152?from=github)| |僅使用 CSS 翻轉 UNO 卡片 | HTML, CSS | [連結](https://projectlearn.io/learn/web-development/project/flipping-uno-cards-using-only-css-151?from=github)| |使用 Redis、WebSocket 和 Go 的聊天應用程式 | Redis、Web Socket、Go、Azure | [連結](https://projectlearn.io/learn/web-development/project/chat-app-with-redis,-websocket-and-go-146?from=github)| |使用 React 導航的 Spotify 登錄動畫 |React、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/spotify-login-animation-with-react-navigation-145?from=github)| |僅使用 CSS 的動態天氣界面 | HTML, CSS | [連結](https://projectlearn.io/learn/web-development/project/dynamic-weather-interface-with-just-css-144?from=github)| |使用 Airtable 和 Vue 的簡單 CRUD 應用程式 | Airtable、Vue、Vuetify、API、HTML | [連結](https://projectlearn.io/learn/web-development/project/simple-crud-app-with-airtable-and-vue-143?from=github)| |帶有 MEVN 堆棧的全棧 RPG 角色生成器 | MongoDB、Express、Vue、Node、HTML | [連結](https://projectlearn.io/learn/web-development/project/full-stack-rpg-character-generator-with-mevn-stack-142?from=github)| |帶有 PERN 堆棧的 Todo 應用 | PostgreSQL、Express、React、Node、HTML | [連結](https://projectlearn.io/learn/web-development/project/todo-app-with-the-pern-stack-141?from=github)| |帶有 Gatsby 的夏季公路旅行地圖應用程式 |React,Gatsby,Leaflet | [連結](https://projectlearn.io/learn/web-development/project/summer-road-trip-mapping-app-with-gatsby-140?from=github)| |使用 Socket.io 的多人紙牌遊戲 | Phaser 3、Express、Socket.io、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/multiplayer-card-game-with-socket.io-139?from=github)| |帶有 Gatsby 的 COVID-19 儀表板和地圖應用程式 |React,Gatsby,Leaflet | [連結](https://projectlearn.io/learn/web-development/project/covid-19-dashboard-and-map-app-with-gatsby-138?from=github)| | React 抽認卡測驗 |React、API、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/flashcard-quiz-with-react-125?from=github)| |用純 JavaScript 打地鼠 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/whack-a-mole-with-pure-javascript-124?from=github)| |使用 JavaScript 的諾基亞 3310 貪吃蛇遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/nokia-3310-snake-game-using-javascript-123?from=github)| |原版 JavaScript 中的石頭剪刀布 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/rock-paper-scissors-in-vanilla-javascript-122?from=github)| |純 JavaScript 的俄羅斯方塊 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/tetris-with-pure-javascript-121?from=github)| |使用 React 製作 Meme Maker |React,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/meme-maker-with-react-119?from=github)| |使用 React 克隆 Evernote |React、Firebase、Node、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/evernote-clone-with-react-118?from=github)| |開發者 Meetup App with Vue | Vue、Firebase、Vuetify、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/developer-meetup-app-with-vue-117?from=github)| | Vue 實時聊天應用 | Vue、Firebase、Vuex、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/real-time-chat-app-with-vue-116?from=github)| |使用 Vue 的加密貨幣追踪器 | Vue、Vuetify、API、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/cryptocurrency-tracker-with-vue-115?from=github)| | Vue 多人問答遊戲 | Vue、Pusher、Node、Express、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/multiplayer-quiz-game-with-vue-114?from=github)| | Vue 掃雷遊戲 | Vue、Vuex、Vuetify、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/minesweeper-game-with-vue-113?from=github)| |使用 Vue 克隆 Instagram | Vue、CSSGram、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/instagram-clone-with-vue-112?from=github)| |使用 Angular 克隆黑客新聞 |角度、燈塔、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/hacker-news-clone-with-angular-111?from=github)| |聊天界面 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/chat-interface-110?from=github)| |純 CSS3 工具提示 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/pure-css3-tooltip-109?from=github)| |社交媒體按鈕 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/social-media-buttons-108?from=github)| |推薦卡 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/testimonial-card-107?from=github)| |帶有 CSS3 Flexbox 的導航欄 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/navigation-bar-with-css3-flexbox-106?from=github)| |使用 CSS3 Flexbox 的移動應用程式佈局 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/mobile-app-layout-with-css3-flexbox-105?from=github)| |受 Reddit 啟發的加載微調器 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/reddit-inspired-loading-spinner-104?from=github)| |帶 CSS3 網格的日曆 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/calendar-with-css3-grid-103?from=github)| | React 中的俄羅斯方塊遊戲 |React,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/tetris-game-in-react-102?from=github)| | 2D 突圍遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/2d-breakout-game-101?from=github)| |精靈動畫 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/sprite-animation-100?from=github)| |蛇遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/snake-game-99?from=github)| |記憶遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/memory-game-98?from=github)| |簡單的身份驗證和授權 | GraphQL、Apollo、Node、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/simple-authentication-and-authorization-97?from=github)| |加密貨幣追踪器 | NextJS、GraphQL、Apollo、Node、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/cryptocurrency-tracker-96?from=github)| |使用 Vanilla Javascript 進行即時搜尋 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/instant-search-with-vanilla-javascript-95?from=github)| |計算器應用 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/calculator-app-94?from=github)| |待辦事項 | Vue、JavaScript、CSS3、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/todo-app-45?from=github)| |博客應用 | Vue、GraphQL、阿波羅、JavaScript、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/blog-app-44?from=github)| |簡單的預算應用程式 | Vue、布爾瑪、JavaScript、CSS3、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/simple-budgeting-app-43?from=github)| |搜尋機器人 |Node、Twilio、Cheerio、API、自動化 | [連結](https://projectlearn.io/learn/web-development/project/search-bot-42?from=github)| |推特機器人 |Node、JavaScript、API、自動化 | [連結](https://projectlearn.io/learn/web-development/project/twitter-bot-41?from=github)| |實時 Markdown 編輯器 |Node、JavaScript、Express、Redis、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/real-time-markdown-editor-40?from=github)| |待辦事項 | Angular、TypeScript、RxJS、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/todo-app-39?from=github)| |黑客新聞客戶端 |角度、RxJS、Webpack、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/hacker-news-client-38?from=github)| |隨機報價機 |React,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/random-quote-machine-37?from=github)| | Todoist克隆| React, Firebase, JavaScript, 測試, HTML5 | [連結](https://projectlearn.io/learn/web-development/project/todoist-clone-36?from=github)| |帶有情感分析的聊天應用 | NextJS、Pusher、Sentiment、Node、React | [連結](https://projectlearn.io/learn/web-development/project/chat-app-with-sentiment-analysis-35?from=github)| |預約安排 | React、Twilio、CosmicJS、Material-UI、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/appointment-scheduler-34?from=github)| |生命遊戲 |React、2D、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/game-of-life-33?from=github)| |新聞應用 | React Native、Node、API、React、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/news-app-32?from=github)| |聊天應用 | React、Redux、Redux Saga、Web 套接字、Node | [連結](https://projectlearn.io/learn/web-development/project/chat-app-31?from=github)| |待辦事項 | React Native、GraphQL、Apollo、API、Hasura | [連結](https://projectlearn.io/learn/web-development/project/todo-app-30?from=github)| | Chrome 擴展 |React,包裹,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/chrome-extension-29?from=github)| |電影投票應用 | React、Redux、API、不可變、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/movie-voting-app-27?from=github)| |特雷洛克隆 | React、Elixir、Phoenix、JWT、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/trello-clone-25?from=github)| | Wiki 風格的 CMS | C#、.NET、Razor 頁面 | [連結](https://projectlearn.io/learn/web-development/project/wiki-style-cms-18?from=github)| |使用 ReactJS 克隆 Spotify |React,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/spotify-clone-with-reactjs-15?from=github)| |微軟主頁克隆 | HTML5、CSS3、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/microsoft-homepage-clone-14?from=github)| |簡單甘特圖 | HTML5、CSS3、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/simple-gantt-chart-13?from=github)| |工作抓取應用 |Node、JavaScript、REST、API、Express | [連結](https://projectlearn.io/learn/web-development/project/job-scraping-app-12?from=github)| |電子商務應用 |React,引導程序,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/e-commerce-app-11?from=github)| | Netflix 著陸頁 | HTML5、CSS3、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/netflix-landing-page-10?from=github)| |人工智能聊天機器人 | Web 語音 API、Node、JavaScript、Express、Socket.io | [連結](https://projectlearn.io/learn/web-development/project/ai-chatbot-9?from=github)| |社交網絡應用 |React、Node、Redux、Firebase、REST | [連結](https://projectlearn.io/learn/web-development/project/social-networking-app-8?from=github)| |在 Node.js 中建置一個簡單的加密貨幣區塊鏈 |Node、JavaScript、密碼學、區塊鏈 | [連結](https://projectlearn.io/learn/web-development/project/build-a-simple-cryptocurrency-blockchain-in-node.js-7?from=github)| | BT 客戶端 |Node、JavaScript、TCP、計算機網絡 | [連結](https://projectlearn.io/learn/web-development/project/bittorrent-client-6?from=github)| |使用 JavaScript 的待辦事項列表應用 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/todo-list-app-with-javascript-4?from=github)| |使用 Anime.js 的 JavaScript 動畫 | JavaScript、CSS3、庫、HTML5、API | [連結](https://projectlearn.io/learn/web-development/project/javascript-animations-with-anime.js-3?from=github)| |帶有 React 的工作板應用程式 |React、Node、Cron、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/job-board-app-with-react-1?from=github)| ### 移動開發: |專案 |技術 |連結 | | :--- |:---|:---| |使用 React Native 建置一個 Uber Eats 克隆 | React Native、Javascript、Android、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/build-an-uber-eats-clone-with-react-native-204?from=github)| |使用 React Native 建置一個 Uber 克隆 | React Native、Javascript、Android、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/build-an-uber-clone-with-react-native-203?from=github)| |使用 Flutter SDK 建置帶有故事的聊天應用程式 |顫振,飛鏢 | [連結](https://projectlearn.io/learn/mobile-development/project/build-a-chat-app-with-stories-using-the-flutter-sdk-199?from=github)| |建置 Robinhood 風格的應用程式來跟踪 COVID-19 病例 |科特林, 安卓 | [連結](https://projectlearn.io/learn/mobile-development/project/build-a-robinhood-style-app-to-track-covid-19-cases-198?from=github)| | Tinder 風格的 Swipe 移動應用程式 |科特林、Java、斯威夫特 | [連結](https://projectlearn.io/learn/mobile-development/project/tinder-style-swipe-mobile-app-186?from=github)| |加密貨幣價格列表移動應用程式 | React Native、Swift、Flutter、Dart | [連結](https://projectlearn.io/learn/mobile-development/project/cryptocurrency-price-listing-mobile-app-185?from=github)| |餐廳社交移動應用程式 | React Native、Swift、Flutter、Dart | [連結](https://projectlearn.io/learn/mobile-development/project/restaurants-social-mobile-app-184?from=github)| |休息時間提醒移動應用 | React Native、Kotlin、Java、Swift | [連結](https://projectlearn.io/learn/mobile-development/project/break-time-reminder-mobile-app-183?from=github)| |發票和付款提醒移動應用程式 | React、Node、Express、MongoDB | [連結](https://projectlearn.io/learn/mobile-development/project/invoicing-and-payment-reminder-mobile-app-182?from=github)| |倒計時移動應用 | Swift、Java、React Native | [連結](https://projectlearn.io/learn/mobile-development/project/countdown-mobile-app-181?from=github)| |使用 Swift 的 Flappy Bird iOS 遊戲 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/flappy-bird-ios-game-using-swift-130?from=github)| |使用 Swift 的 Bull's Eye iOS 遊戲 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/bull's-eye-ios-game-using-swift-129?from=github)| |使用 SwiftUI 的任務列表 iOS 應用 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/task-list-ios-app-using-swiftui-128?from=github)| |使用 SwiftUI 的餐廳 iOS 應用 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/restaurant-ios-app-using-swiftui-127?from=github)| |使用 Swift 的骰子 iOS 應用 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/dice-ios-app-with-swift-126?from=github)| | TrueCaller 克隆 | Java、MySQL、XAMPP、Android | [連結](https://projectlearn.io/learn/mobile-development/project/truecaller-clone-83?from=github)| |天氣應用 | Java, API, Android | [連結](https://projectlearn.io/learn/mobile-development/project/weather-app-82?from=github)| |電子商務應用 | Java、Firebase、Android | [連結](https://projectlearn.io/learn/mobile-development/project/e-commerce-app-81?from=github)| |聊天應用 | Java、Firebase、Android | [連結](https://projectlearn.io/learn/mobile-development/project/chat-app-80?from=github)| |待辦事項 | Flutter、Dart、Android、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/todo-app-79?from=github)| |旅遊應用程式用戶界面 | Flutter、Dart、Android、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/travel-app-ui-78?from=github)| | Reddit 客戶端 |安卓,科特林 | [連結](https://projectlearn.io/learn/mobile-development/project/reddit-client-46?from=github)| |待辦事項 | React Native、Android、iOS、JavaScript | [連結](https://projectlearn.io/learn/mobile-development/project/todo-app-24?from=github) |照片庫查看器 | C#、iOS、Xamarin、Visual Studio、Android | [連結](https://projectlearn.io/learn/mobile-development/project/photo-library-viewer-19?from=github)| |使用 React Native 克隆 WhatsApp | React Native、Node、GraphQL、Apollo、JavaScript | [連結](https://projectlearn.io/learn/mobile-development/project/whatsapp-clone-with-react-native-2?from=github)| ### 遊戲開發: |專案 |技術 |連結 | | :--- |:---|:---| |使用 Kaboom.js 建置超級馬里奧兄弟、塞爾達傳說和太空侵略者 | JavaScript,Kaboom | [連結](https://projectlearn.io/learn/game-development/project/build-super-mario-bros,-zelda,-and-space-invaders-with-kaboom.js-201?from=github) | |使用 TypeScript 建立打磚塊遊戲 |打字稿、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/game-development/project/create-an-arkanoid-game-with-typescript-195?from=github)| |簡單遊戲 | Lua、LÖVE、Python、Pygame 零 | [連結](https://projectlearn.io/learn/game-development/project/simple-games-179?from=github)| | Python在線多人遊戲|蟒蛇 | [連結](https://projectlearn.io/learn/game-development/project/python-online-multiplayer-game-173?from=github)| |打敗他們格鬥遊戲 |統一,C# | [連結](https://projectlearn.io/learn/game-development/project/beat-em-up-fight-game-172?from=github)| |使用 Godot 3.1 的簡單 3D 遊戲 |戈多,C#,3D | [連結](https://projectlearn.io/learn/game-development/project/simple-3d-game-using-godot-3.1-150?from=github)| | Godot 中的簡單益智遊戲- Box and Switch |戈多,C#,二維 | [連結](https://projectlearn.io/learn/game-development/project/simple-puzzle-game-in-godot---box-and-switch-149?from=github)| | Godot 3 中的遊戲界面從頭開始 |戈多,C#,二維 | [連結](https://projectlearn.io/learn/game-development/project/game-interface-from-scratch-in-godot-3-148?from=github)| | Godot 的 2D 遊戲:玩家與敵人 |戈多,C#,二維 | [連結](https://projectlearn.io/learn/game-development/project/2d-game-with-godot:-player-and-enemy-147?from=github)| |使用 Socket.io 的多人紙牌遊戲 | Phaser 3、Express、Socket.io、JavaScript | [連結](https://projectlearn.io/learn/game-development/project/multiplayer-card-game-with-socket.io-139?from=github)| |使用 Unity 2D 和 Mirror 的多人紙牌遊戲 | C#、Unity、二維、鏡像 | [連結](https://projectlearn.io/learn/game-development/project/multiplayer-card-game-with-unity-2d-and-mirror-137?from=github)| | Rust 中的 Roguelike 教程 |生鏽,二維 | [連結](https://projectlearn.io/learn/game-development/project/roguelike-tutorial-in-rust-136?from=github)| | Rust 歷險記 - 一款基本的 2D 遊戲 |生鏽,二維 | [連結](https://projectlearn.io/learn/game-development/project/adventures-in-rust---a-basic-2d-game-135?from=github)| |使用 Ruby 的終端貪吃蛇遊戲 |紅寶石,二維 | [連結](https://projectlearn.io/learn/game-development/project/terminal-snake-game-with-ruby-134?from=github)| |使用 OpenGL 的太空入侵者 | OpenGL、C/C++、2D | [連結](https://projectlearn.io/learn/game-development/project/space-invaders-using-opengl-133?from=github)| | C 中的數獨求解器 | C/C++, 二維 | [連結](https://projectlearn.io/learn/game-development/project/sudoku-solver-in-c-132?from=github)| | C 中的國際象棋引擎 | C/C++, 二維 | [連結](https://projectlearn.io/learn/game-development/project/chess-engine-in-c-131?from=github)| |使用 Swift 的 Flappy Bird iOS 遊戲 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/game-development/project/flappy-bird-ios-game-using-swift-130?from=github)| |使用 Swift 的 Bull's Eye iOS 遊戲 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/game-development/project/bull's-eye-ios-game-using-swift-129?from=github)| |用純 JavaScript 打地鼠 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/whack-a-mole-with-pure-javascript-124?from=github)| |使用 JavaScript 的諾基亞 3310 貪吃蛇遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/nokia-3310-snake-game-using-javascript-123?from=github)| |原版 JavaScript 中的石頭剪刀布 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/rock-paper-scissors-in-vanilla-javascript-122?from=github)| |純 JavaScript 的俄羅斯方塊 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/tetris-with-pure-javascript-121?from=github)| | Vue 多人問答遊戲 | Vue、Pusher、Node、Express、JavaScript | [連結](https://projectlearn.io/learn/game-development/project/multiplayer-quiz-game-with-vue-114?from=github)| | Vue 掃雷遊戲 | Vue、Vuex、Vuetify、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/game-development/project/minesweeper-game-with-vue-113?from=github)| | React 中的俄羅斯方塊遊戲 |React,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/game-development/project/tetris-game-in-react-102?from=github)| | 2D 突圍遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/2d-breakout-game-101?from=github)| |精靈動畫 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/sprite-animation-100?from=github)| |蛇遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/snake-game-99?from=github)| |記憶遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/memory-game-98?from=github)| |坦克射手 | 3D、統一、C# | [連結](https://projectlearn.io/learn/game-development/project/tanks-shooter-93?from=github)| | 2D Roguelike |二維、Unity、C# | [連結](https://projectlearn.io/learn/game-development/project/2d-roguelike-92?from=github)| |約翰·萊蒙鬧鬼的短途旅行 3D | 3D、統一、C# | [連結](https://projectlearn.io/learn/game-development/project/john-lemon's-haunted-jaunt-3d-91?from=github)| | VR 初學者:密室逃脫 |虛擬現實、Unity、C# | [連結](https://projectlearn.io/learn/game-development/project/vr-beginner:-the-escape-room-90?from=github)| |露比的冒險 |二維、Unity、C# | [連結](https://projectlearn.io/learn/game-development/project/ruby's-adventure-89?from=github)| |角色扮演遊戲 |二維、Unity、C# | [連結](https://projectlearn.io/learn/game-development/project/rpg-game-88?from=github)| |滾球| 3D、統一、C# | [連結](https://projectlearn.io/learn/game-development/project/roll-a-ball-87?from=github)| | FPS 微型遊戲 |統一,C# | [連結](https://projectlearn.io/learn/game-development/project/fps-microgame-86?from=github)| |平台微遊戲 | Unity、C#、2D | [連結](https://projectlearn.io/learn/game-development/project/platformer-microgame-85?from=github)| |卡丁車小遊戲 |統一,C# | [連結](https://projectlearn.io/learn/game-development/project/karting-microgame-84?from=github)| |街機射擊 | Lua,愛 | [連結](https://projectlearn.io/learn/game-development/project/arcade-shooter-47?from=github)| |生命遊戲 |React、2D、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/game-of-life-33?from=github)| |手工英雄 | C/C++、OpenGL、2D | [連結](https://projectlearn.io/learn/game-development/project/handmade-hero-23?from=github)| |突圍 | C/C++、OpenGL、2D | [連結](https://projectlearn.io/learn/game-development/project/breakout-22?from=github)| |俄羅斯方塊 | C/C++, 二維 | [連結](https://projectlearn.io/learn/game-development/project/tetris-21?from=github)| |紅白機遊戲 | C/C++、Python、二維 | [連結](https://projectlearn.io/learn/game-development/project/nes-game-20?from=github)| | Roguelike 遊戲 | C#、.NET、RogueSharp、MonoGame、RLNet | [連結](https://projectlearn.io/learn/game-development/project/roguelike-game-17?from=github)| |簡單的角色扮演遊戲 | C#、SQL、二維 | [連結](https://projectlearn.io/learn/game-development/project/simple-rpg-game-16?from=github)| ### 機器學習與人工智能: |專案 |技術 |連結 | | :--- |:---|:---| |使用 BeautifulSoup 建置網絡爬蟲 | Python, BeautifulSoup | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/build-a-web-scraper-using-beautifulsoup-202?from=github)| |從胸部 X 光檢測肺炎的 CNN |美國有線電視新聞網,蟒蛇 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/cnn-that-detects-pneumonia-from-chest-x-rays-169?from=github)| |使用 AWS 在 Python 中自動更新資料可視化 | Python、AWS、Matplotlib | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/auto-updating-data-visualizations-in-python-with-aws-158?from=github)| |使用 GCP 和 Node 的 Twitter 情感分析工具 | API、GCP、Node、JavaScript | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/twitter-sentiment-analysis-tool-using-gcp-and-node-156?from=github)| |使用 CNN 進行 Twitter 情緒分析 | Python、Matplotlib、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/twitter-sentiment-analysis-using-cnn-120?from=github)| |泰勒斯威夫特歌詞生成器 | Python、Keras、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/taylor-swift-lyrics-generator-77?from=github)| | MNIST 數字辨識器 | Python、Keras、TensorFlow、Numpy、SciKit | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/mnist-digit-recognizer-76?from=github)| |訓練模型生成顏色 | Python、Keras、TensorFlow、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/train-a-model-to-generate-colors-75?from=github)| |圖片說明生成器 | Python、TensorFlow、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/image-caption-generator-74?from=github)| |使用 CNN 破解驗證碼系統 | Python、Keras、TensorFlow、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/break-a-captcha-system-using-cnn-73?from=github)| |生成一張平均臉 | Python、OpenCV、Numpy、C/C++ | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/generate-an-average-face-72?from=github)| |圖像拼接 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/image-stitching-71?from=github)| |手部關鍵點檢測 | Python、OpenCV、Numpy、C/C++ | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/hand-keypoint-detection-70?from=github)| |特徵臉 | Python、OpenCV、Numpy、C/C++ | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/eigenface-69?from=github)| |無人機目標檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/drone-target-detection-68?from=github)| |使用 Mask R-CNN 進行目標檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/object-detection-using-mask-r-cnn-67?from=github)| |面部地標檢測 | Python、OpenCV、DLib、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/facial-landmark-detection-66?from=github)| |文本傾斜校正 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/text-skew-correction-65?from=github)| | OCR 和文本辨識 | Python、OpenCV、Tesseract、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/ocr-and-text-recognition-64?from=github)| |人數統計 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/people-counter-63?from=github)| |文本檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/text-detection-62?from=github)| |語義分割 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/semantic-segmentation-61?from=github)| |物件跟踪 | Python、OpenCV、Numpy、CamShift | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/object-tracking-60?from=github)| |人臉聚類 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/face-clustering-59?from=github)| |條碼掃描儀 | Python、OpenCV、ZBar、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/barcode-scanner-58?from=github)| |顯著性檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/saliency-detection-57?from=github)| |人臉檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/face-detection-56?from=github)| |文件掃描儀 | Python、OpenCV、Numpy、SciKit | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/document-scanner-55?from=github)| |音樂推薦 | Python、SciKit、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/music-recommender-54?from=github)| |預測葡萄酒質量 | Python、Matplotlib、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/predict-quality-of-wine-53?from=github)| |遺傳算法 | Python、SciKit、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/genetic-algorithms-52?from=github)| |深夢 | Python、TensorFlow、可視化 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/deepdream-51?from=github)| |股價預測| Python、SciKit、Matplotlib | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/stock-price-prediction-50?from=github)| |電影推薦系統 | Python, LightFM | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/movie-recommendation-systems-49?from=github)| | Twitter 情緒分析 | Python, API | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/twitter-sentiment-analysis-48?from=github)| |帶有情感分析的聊天應用 | NextJS、Pusher、Sentiment、Node、React | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/chat-app-with-sentiment-analysis-35?from=github)| --- **結論** 2023 年將成為令人振奮的發展年,新技術和工具層出不窮。 希望這篇文章對您有幫助。

給開發者的 15 份好用 Cheatsheets 分享

隨著程式設計技術的快速發展,我們必須學習很多新東西。有些語言和框架非常複雜,您可能記不住所有的語法或方法。備忘單就是您易於存取的筆記了。 每當有人發現任何有幫助或有價值的事情時,我們都會做筆記。但是,您不需要對在書籍、研討會或文章中看到的每個細節都做筆記。 為了幫助您學習,我編寫了這份頂級備忘單列表。 - 原文出處:https://dev.to/ishratumar/15-must-have-cheatsheets-for-developers-1n92 --- ## HTML, CSS, and JavaScript Cheatsheet 您可以在此處找到 HTML、CSS 和 JavaScript 程式碼範例。每個例子都有一個解釋。像這樣的備忘單是我的最愛之一。 連結:https://htmlcheatsheet.com/js/ ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/msaqyef5m5nkk3op6oq8.jpg) ## JavaScript Cheatsheet 這是對初學者的 JavaScript 的完整、快速的介紹。值得看一下。 連結:https://quickref.me/javascript ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bbhfqsoinyj3142ix5z7.jpg) ## React.js Cheatsheet React 是最流行的 JavaScript 函式庫。對於 React 愛好者來說,這是一個簡單但有用的備忘單。一定要將它加入書籤,以便快速參考。 連結:https://devhints.io/react/ ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1i30duid59mry623p8ee.jpg) ## Cheatography 沒有比這更好的資源了。它有超過 5,000 個備忘單、修訂輔助工具和快速參考!每個人都可以在這裡得到他們需要的一切,而不僅僅是軟體工程師。在這裡,您可以找到有關 Web 開發、商業、遊戲、健康、數位行銷等的備忘單。 連結:https://cheatography.com/ ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9oqaebo7kjce31dc3klp.jpg) ## Java Cheat Sheets 此處簡要列出了教科書中使用最多的 Java 語言特性和 API。這是一個很好的快速參考。 連結:https://introcs.cs.princeton.edu/java/11cheatsheet/ ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0hfa25tmgbd263f0biwk.jpg) ## OverAPI Over API 是一個了不起的資源。對於大多數編程語言,您可以在此處找到備忘單。 連結:https://overapi.com/ ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dv049973s0b5jgk5jroy.jpg) ## Devhints 這裡有一些範例、連結、片段等,可讓您簡要了解該語言的基礎知識。在一頁上,您會找到詳細的說明。值得研究。 連結:https://devhints.io/ ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u3l5nr66wiwvruv1iyga.jpg) ## Gitsheet Git 是開發人員應具備的最重要的技能。這是一個非常簡單的 git 命令備忘單。如果您可以存取此 Gitsheet,則無需記住所有命令。 連結:https://gitsheet.wtf/ ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gcf2ah61erkjkzov13nw.jpg) ## Vue.js cheatsheet 此備忘單包含 Vue.js 的詳細程式碼片段和解釋。它包括與屬性、DOM、資料、事件、生命週期、API 等相關的片段。如果您正在尋找 Vue.js 的快速參考,請檢查一下。 連結:https://marozed.com/vue-cheatsheet/ ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9uq2dcd2i3wxfhjef8b.jpg) ## HTML5 Canvas Cheat Sheet 可在此處找到 HTML5 Canvas 的程式碼示例,包括其元素、2D 上下文、線條樣式、顏色、陰影等。在此處了解有關 HTML 畫布的所有訊息。 連結:https://simon.html5.org/dump/html5-canvas-cheat-sheet.html ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2a8tz7vnxr0ec5huaylb.jpg) ## Web 開發人員的 SEO 備忘單 這個網站是關於 SEO(搜尋引擎優化)的。在最有效的搜尋引擎優化技巧中,這是最有用的快速參考之一。 Web 開發人員和軟體工程師也受益於輕鬆存取 SEO 技術標準。 連結:https://moz.com/learn/seo ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izmc3x46eyc1rdvy90tf.jpg) ## Easing functions 通過使用緩動函數,您可以調整動畫的速度以建立各種效果,例如彈跳、減速、放大等。有關詳細訊息,請參閱此 Microsoft 文件。 此外,參數隨時間變化的速率由緩動函數指定。現實世界中的物體幾乎從不以一致的速度移動,也很少突然開始和結束。使用此頁面,您可以選擇理想的緩動函數。 連結:https://easings.net/en# ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/58cd8pj9bj0m44qd1cth.jpg) ## CSS3 動畫 這個網站有一些驚人的動畫效果,你可以在你的下一個專案中使用。 連結:http://www.justinaguilar.com/animations/# ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/75v2qv333wzgw8qo5019.jpg) ## CSS 網格 CSS 網格可能有點挑戰性。因此,很難記住它的所有屬性。您可以將此備忘單加入到您的書籤中以供快速參考。 連結:https://grid.malven.co/ ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m2zj6k2wrtb0pszd1u7n.jpg) --- 以上,簡單分享,希望對您有幫助!

前 Netflix 資深工程師:爲什麼我會辭掉年薪 $450,000 美元的工作

Michael Lin 是前網飛資深工程師,年薪高達 45 萬美元,約合新台幣 1300 萬元 但是他在工作四年後離職了,並且在網路上分享了心得 - 原文出處:https://dev.to/_michaellin/why-i-quit-a-450000-engineering-job-at-netflix-1f0g --- ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ucmypesj5zywleeojx92.png) > 金手銬 —— 你留在一份你寧願辭職、只是為了錢而待著的工作。 我以為我會永遠留在 Netflix。市場上薪酬最高。講求自由與責任。無限帶薪假期。你還能要求什麼呢? 所以當我在 2021 年 5 月離開 Netflix 時,每個人都認為我瘋了。我父母首先反對。他們來自文化大革命時期的中國,當時幾乎沒有足夠的食物吃,他們認為我正在拋棄他們來到美國所經歷辛苦的一切。 “低下頭去幹活就對了!”他們說。 “不要對你所擁有的不知感恩!”他們說。 我的朋友們也不相信。 “有一堆免費食物欸!” “FAANG 巨頭欸!” “帶著慢慢領股票呀!” 我聽到的唯一讓我略微停頓的反對論點,來自我在 Netflix 的導師。他說我不應該在沒有找到另一份工作的情況下辭職,因為“我會放棄我在 Netflix 的高薪所擁有的影響力。” ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lb8qyf1sxngv1xeateei.png) > 一邊休息一邊慢慢領股票 這讓我停頓了整整 3 天,但我還是放棄了。8 個月後的現在,我 100% 確定這是正確的決定。 在這篇文章中,我想談談幫助我了解金手銬真正成本的 3 個因素,以及為什麼每年 50 萬美元的薪水也無法讓我繼續從事我不再喜歡的工作。 ## 一個失敗的角色轉換 隨著辦公室於 2020 年 3 月關閉,工作中所有最好的部分 ——社交、同事、津貼,都消失了。 而你剩下的就是工作本身。因此,如果您不喜歡這份工作,而這就是您的全部,那麼 COVID 會將這一事實放大 10 倍以上。 而且我不喜歡這份工作。但原本不是這樣的。 我在 Netflix 工作了將近 4 年,擔任用戶增長方面的資深軟體工程師。一開始,我覺得自己得到了豐厚的報酬來學習。工作了 1.5 年左右,我都喜歡它。 Netflix 的文化與我之前在亞馬遜經歷過的更為隱秘的文化截然不同。每個產品決策的備忘錄都可供所有員工閱讀。這就像拿錢去讀 MBA。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2amgontvgl7nkhlkecsf.png) > Netflix 對其所有產品決策的透明度是在那裡工作的最佳福利之一。這與蘋果和亞馬遜更為隱秘的文化形成鮮明對比。 但是在我的後半段時間裡,工程工作開始感覺像是複制粘貼。 需要啟動一個新的微服務? 複製粘貼一個舊的,更改業務邏輯,你就完成了。 新的 A/B 測試? 複製粘貼舊的,更改一些測試變體,就完成了。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8g1j19x9dvj8lvbga9wk.png) > Netflix 非常喜歡 A/B 測試。這是他們從主頁(來自 Netflix 技術部落格)測試的 CTA 的 4 個變體 我覺得毫無疑問工程可以為 Netflix 所用,但我覺得更好的問題是,某個特定專案是否充分利用了工程資源。所以我想過渡到產品管理,在那裡我可以領導這些工作。我花了 2 年的時間在公司轉了一圈,不停地建立聯繫,與每個組織交談,併申請我能找到的每一個職位。 當我向每個組織申請時,我提交了關於我作為 PM 的優先事項的建議:客戶服務、開發人員生產力、工作室、合作夥伴關係和通知。我建議在我自己的團隊中建立一個角色來幫助管理不斷增長的基礎設施。我還建議其他 PM 可以將更多工作委託給我,這樣他們就可以騰出時間來發展他們的組織。所有這些提議最終都沒有成功。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rchwbz4agbjhitt38tiq.png) > 我花了 2 年的時間兜圈子試圖在 Netflix 找到一份 PM 的工作,但最終落得一場空。 回過頭來看,我意識到自己的錯誤。我想如果我再努力一點,我最終會得到這份工作。但現在我意識到,有時由於結構性問題,事情超出了你的控制。 Netflix 沒有適當的流程來支持這樣的橫向角色變更;我從未見過工程師在這裡成功過渡到產品管理。 他們為我提供了更多與產品管理合作的機會,以培養產品技能,對此我深表感謝。但合作與擁有角色本身不同。歸根結底,你不能只讀一本關於游泳的書就指望學會游泳。你必須跳入水中。 ## 動力減弱,表現減弱 在我失敗的 PM 求職接近尾聲時,我覺得高薪是一個越來越糟糕的優點。原本是在賺錢和學習。現在我只是在賺錢。 我團隊的目標和我的興趣也開始出現分歧。我的團隊正在朝著涉及平台遷移的更注重工程的方向發展。但我的興趣更多地轉向創業和產品管理。我分配的工程工作永遠不會適用於我以後所做的任何其他工作。 我開始覺得我又犯了以前的職業錯誤 - 在一份不適合我的工作上待的時間比我應該做的要長。這個錯誤的代價比人們想像的要高。如果你在一份你想離開的工作上多呆了兩年,並且在你的一生中做了 5 份以上的工作,那麼你只是在你不想做的工作上浪費了你生命中的 10 年。我覺得我在浪費時間。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mz85i3mpvnky6zos5qye.png) > 沒有什麼比錯過工作訊息更讓人焦慮的了。 我的動力減弱了,我的表現也隨之減弱。我越來越少參加會議,盡量減少做任何與開發產品管理技能不直接相關的工作,並在溝通方面拖拖拉拉。最後唯一的動機就是不想被解僱。感覺我已經達到了我的目標是這麼低的標準,甚至努力跨越它,這讓我有點難過。 不幸的是,我的經理開始注意到了。在持續 2 個多小時的激烈績效評估中,他告訴我,我需要 1) 更多地參與這次遷移,以及 2) 更加溝通。用他的話說,“如果我想留在團隊中”,我必須在這些方面有所改進。 ## 重新評估 COVID-19 期間的生活優先事項 疫情大流行是一記警鐘。 看著數以百萬計的人死於 COVID 讓我意識到明天是無法保證的。在您的任何夢想實現之前,您可能會死於 COVID。你推遲夢想的時間越長,它永遠不會實現的風險就越大。所以如果有什麼你想要的,你必須現在就去做。 不想再說晚點才是時候了。現在就是時候。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5oawd1k9a5lnzses4is3.png) > 被推遲的夢想就是被拒絕的夢想。我一直以來最喜歡的名言。 我意識到金手銬的真正代價是什麼。代價是你的青春,你的時間,你的生命。人們不會準確判斷這些成本,因為薪水是一個硬數字,而你的青春價值更無形。但僅僅因為某些東西難以衡量,並不意味著它的價值就低於金錢等可數的東西。很難衡量品牌、心理健康或愛情的價值,但我們知道這很重要。 看到所有這些人死於 COVID,我害怕有一天我的墓碑上會寫著: > “這裡躺著 Michael。他一生都在做他不想做的工作。然後他感染了 COVID 接著就死掉了。祝安息。” 我在一份我不喜歡的工作上待的時間越長,這成為我墓碑的可能性就越大。我知道我現在必須採取行動 - 我不能一直把棘手的職業問題推到一邊。我不得不辭職。 ## 最後的日子 我把糟糕的績效評估和被解僱的威脅當成是一種解脫。但我想在不被解僱的情況下先拿到遣散費。 因此,幾週後,我在一對一面談中,向我的經理提案,我們討論了“先發制人的遣散費方案”。 我這樣說:“我的表現在下降,因為我的動力在下降。我沒看到我的積極性有可能提高,因為團隊的目標與我的職業目標背道而馳。如果我們現在討論 Netflix 的先發制人遣散費而不是拖延下去會怎麼樣?這樣 Netflix 就可以省錢,你可以更快地找到更適合團隊的人選,我也可以去做我想做的事。對每個人來說都是雙贏的局面。” ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpr7oownjm47eomrnyne.png) > 掙脫束縛。 在他與 HR 討論後,我與他和 HR 進行了最後一次會面,他們同意先發制人地解僱我,然後我拿到了最後的遣散費。金手銬 —— 再見了。 ## Netflix 之後的生活 我以為離開公司我的生活就結束了,但事實恰恰相反。我擔心我會沒有社交生活,但實際上我在退出後遇到了更多的人 —— 其他的創業者、企業家和建設者。 我看到我的心理健康得到改善,因為如果我錯過了另一封電子郵件或 slack 訊息,我因擔心而產生的焦慮消失了。 我現在感到內心深處的平靜,一種堅定的信念,即一切都會好起來的,即使現在不能保證未來的成功。當我在周日晚上打字時,如果工作對我有利,我對周末工作沒有任何問題。沒有比知道我掌握了自己工作的所有價值更好的動力了。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gvzbuxd6dx1klb8a6mdz.png) 通過只做讓我充滿活力的事情,它可能會諷刺地釋放比我以前賺的更多的潛在收入。 我從 2021 年 5 月辭職已經 8 個月了。我在 2021 年剩下的時間裡休息了一段時間。我在紐約住了幾個月,在猶他州和亞利桑那州進行了一次公路旅行,總體上很享受生活。 我決定全身心地為自己工作。雖然我才剛剛起步,沒有任何真正可靠的收入來源,但我會相信這個過程,如果我致力於讓我充滿活力的事情,好事就會發生。 --- 我現在真的相信,安全行事是最冒險的選擇。當你謹慎行事時,你同樣會暴露在所有的危險之中,而且沒有向上的機會。正如海倫凱勒曾經說過的: ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srvmeb69o4owf6mhgu66.png) > 謹慎行事是最冒險的選擇。

利用新版 React 文件來學習並精通 functional components

**舊的 React 文件幾乎沒什麼用,這大家都知道,因為它沒反映該框架的現代用法。在本文中,我們將探索它的新文件並討論它為何很棒。** 原文出處:https://dev.to/diogorodrigues/reacts-new-killer-documentation-focused-only-on-functional-components-jnk --- React Hooks 與 [2019 年初版本 16.8](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html) 一起發布,迅速流行起來並在前端社區中得到廣泛採用。通過這個版本,使用基於類別的元件編寫的複雜性,被有狀態的功能元件所取代。雖然我們可以在文件中找到對這些新功能的很好解釋,但大多數範例都繼續使用類別。 現在,在發生革命性變化 3 年多之後,**React 發布了其文件的 BETA 版本,從其解釋中刪除了類別,專注於使用帶有互動範例的鉤子的現代開發方式。** > “一旦我們與現有的 React 文檔達到內容一致,我們的目標是將此網站切換為主要網站。舊的 React 網站將存檔在一個子域中,因此您仍然可以存取它。舊內容鏈接將重定向到存檔的子域,該子域將有關於過時內容的通知。” - [BETA React 文檔](https://beta.reactjs.org/) _P.S.重要的是,當我寫這篇文章時,新內容幾乎 100% 完成了。_ ## 你可以在新的 React 文檔中找到什麼 雖然這個 React BETA 文檔不是很廣泛,但我不會逐個主題地介紹它,我將在下面重點介紹它的一些主要優點。 ### Quick Start 真的是非常快速的開始 **對我來說,這是改善超多的部分,因為與舊版本不同,現在我們可以通過其文檔中的互動式程式碼範例來使用 React 程式碼。** 這不是很神奇嗎? 一個完整的介紹,非常簡單,解釋清楚,並且不需要為現在開始學習的人設置任何專案。 ![React文檔交互示例演示](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxsurynvrjpurbhla7pr.gif) ### 很好地解釋了使用 React Effects 的最佳方式 就個人而言,我認為**他們為解釋 Effects 所做的工作非常出色。**這確實是我研究了很多的東西,肯定會幫助我使用 React 開發更好的程式碼。 有一些詳盡的頁面展示了[如何停止將 Effects 視為生命週期掛鉤](https://beta.reactjs.org/learn/lifecycle-of-reactive-effects),而是 [Effects 作為與外部系統的同步器](https://beta.reactjs.org/learn/synchronizing-with-effects)。發生這種混淆是因為我們習慣於將使用 useEffect 鉤子的功能組件與基於類別的元件生命週期進行比較,但這不再有意義了。 https://twitter.com/dan_abramov/status/1157250198659354624 **另一個令人驚嘆的內容是 [“你可能不需要 effect”](https://beta.reactjs.org/learn/you-might-not-need-an-effect) 主題,我們可以在其中了解如何刪除不必要的效果**通過許多用例和互動式程式碼示例。您可以在下面的影片中找到關於該主題的精彩摘要。 https://www.youtube.com/watch?v=bGzanfKVFeU&t=742s&ab_channel=BeJS ### 精通狀態管理 我知道這個標題聽起來太冒險了,但是這個 React BETA 文檔有很多內容是關於[如何更好地建置狀態,避免冗餘狀態相關的錯誤](https://beta.reactjs.org/learn/managing-state),等等。 > “良好地建置狀態可以區分一個易於修改和除錯的元件,以及一個經常產生錯誤的組件。” - React 文檔 查看 [管理狀態部分](https://beta.reactjs.org/learn/managing-state) 以及 [Referencing Values with Refs](https://beta.reactjs.org/learn/referencing-values-with-refs) 主題以更好地理解 React 中狀態的使用。 ### 更多你可以在新的 React 文檔中找到的知識 我想強調的其他一些內容是: - [React API 參考](https://beta.reactjs.org/apis/react) 部分包含所有內容,以便更快地諮詢程式碼片段。 - “[聲明式 UI 與命令式 UI 相比如何](https://beta.reactjs.org/learn/reacting-to-input-with-state#how-declarative-ui-compares-to-imperative )”主題展示瞭如何更好地編寫聲明式 React 元件。 - “[Render and Commit](https://beta.reactjs.org/learn/render-and-commit)” 了解渲染 React 元件過程中的步驟。 - “[排隊一系列狀態更新](https://beta.reactjs.org/learn/queueing-a-series-of-state-updates)”主題將解釋為什麼有時它不起作用以及如何解決它. - “[通過自定義掛鉤重用邏輯](https://beta.reactjs.org/learn/reusing-logic-with-custom-hooks)”了解如何在元件之間共享邏輯。 ## 結論 **從基礎主題到進階主題,這些文檔涵蓋了您學習如何使用最好的現代 React 建立用戶界面所需的一切。**如果您是 React 世界的新手,本文檔肯定會對您有很大幫助互動式範例。對於經驗豐富的 React 開發人員,本文檔匯集了幾個重要的進階概念,這些概念一定會幫助您建立更好的 UI 元件。

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 基本觀念&實務範例:推薦新手參考

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>; } ``` --- 以上是快速整理,希望對您有幫助!