<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          10個 React 開發(fā)避坑指南

          共 10571字,需瀏覽 22分鐘

           ·

          2024-07-13 22:38

              

          大廠技術(shù)  高級前端  Node進階

          點擊上方 程序員成長指北,關(guān)注公眾號

          回復(fù)1,加入高級Node交流群

          說真的,誰還沒遇到過這種事? 你興沖沖地加入一家新公司,面試的時候公司吹得天花亂墜,讓你毅然決然地辭掉了上一份工作。結(jié)果,一周的“假期”過后,你開始正式工作,卻發(fā)現(xiàn)代碼像一團亂麻,各種奇葩的解決方案,缺乏規(guī)范,簡直讓人崩潰!你看著代碼心想:這到底是什么鬼? 我完全看不懂,也不敢輕易修改,生怕改錯一個地方就全盤崩潰。

          雖然這種情況可能不像你想的那么常見,但其實比你想象的還要普遍。為了避免這種挑戰(zhàn),開發(fā)者,尤其是資深開發(fā)者,需要帶頭行動。畢竟,公司高層、技術(shù)負責人、產(chǎn)品經(jīng)理等等,他們沒有時間或者并不優(yōu)先考慮代碼細節(jié),他們更關(guān)心的是為公司創(chuàng)造價值和效益。

          為了避免這種挑戰(zhàn),我在我的項目中一直遵循一些我認為很重要的最佳實踐,并且建議每個人都應(yīng)該學(xué)習。雖然可能沒人會記住你的代碼,但那些進行代碼審查的人肯定會注意到你的細致,并贊賞你的努力。這可能是你在公司中脫穎而出,并獲得晉升的最有效方法之一。

          1. 使用絕對路徑,而不是相對路徑

          剛接手一個新項目,經(jīng)常會看到路徑里全是 ../../../../../. ,這些路徑被稱為相對路徑。雖然可以使用,但并不推薦。最佳實踐是使用絕對路徑,它能提供文件的完整路徑。當然,如果你使用 Webpack 或 TypeScript,需要進行一些配置。

          配置 Webpack (create-react-app):

          如果你使用 create-react-app,配置絕對路徑非常簡單。首先,在項目的根目錄創(chuàng)建一個名為 jsconfig.json 的文件,然后添加以下內(nèi)容:

          {
            "compilerOptions": {
              "baseUrl""src"
            },
            "include": ["src"]
          }

          配置 TypeScript:

          如果你使用 TypeScript,則需要在 tsconfig.json 文件中添加以下配置:

          {
            "compilerOptions": {
              "baseUrl""src",
              "paths": {
                "@/*": ["src/*"]
              }
            },
            "include": ["src"]
          }

          這樣,你就可以將這段代碼:

          import { Button } from '../../../../components/Button'
          import { Icon } from '../../../../components/Icon'
          import { Input } from '../../../../components/Input'

          改成更簡潔、易讀的:

          import { Button } from '@/components/Button'
          import { Icon } from '@/components/Icon'
          import { Input } from '@/components/Input'

          2. 使用“導(dǎo)出桶”組織模塊

          當我看到上面提到的代碼時,我突然想起了一個可以顯著提高代碼可讀性和維護性的技巧——“導(dǎo)出桶”,也稱為“重新導(dǎo)出”。這種方法涉及創(chuàng)建一個名為 index.js (或者如果你使用 TypeScript 則為 index.ts) 的文件,在這個文件中,導(dǎo)出該文件夾中存在的所有模塊。

          舉個例子,假設(shè)你有一個名為 components 的文件夾,里面包含以下文件:Button.tsx、Icon.tsx 和 Input.tsx。使用“導(dǎo)出桶”技術(shù),你需要創(chuàng)建一個 index.ts 文件,并添加以下內(nèi)容:

          export * from './Button'
          export * from './Icon'
          export * from './Input'

          這樣,當你想在頁面或其他模塊中使用這些組件時,就可以一次性導(dǎo)入它們:

          import { Button, Icon, Input } from '@/components'

          這種做法簡化了代碼組織,提高了維護性,因為你不再需要單獨列出每個組件。此外,它使代碼更簡潔易懂,這在中大型項目中至關(guān)重要。

          3. 選擇 “導(dǎo)出默認” 還是 “命名導(dǎo)出”

          當我們深入探討“導(dǎo)出桶”時,需要注意的是,它可能會與“導(dǎo)出默認”的用法沖突。如果不清楚,我會用示例來說明情況:

          讓我們回到我們的組件:

          export const Button = () => {
            return <button>Button</button>
          }
          export default Button
          export const Icon = () => {
            return <svg>Icon</svg>
          }
          export default Icon
          export const Input = () => {
            return <input />
          }
          export default Input

          想象一下,每個組件都在一個單獨的文件中,你想一次性導(dǎo)入它們。如果你習慣了默認導(dǎo)入,你可能會嘗試這樣做:

          import Button from '@/components'
          import Icon from '@/components'
          import Input from '@/components'

          但是,這行不通,因為 JavaScript 無法確定要使用哪個“導(dǎo)出默認”,會導(dǎo)致錯誤。你只能被迫這樣做:

          import Button from '@/components/Button'
          import Icon from '@/components/Icon'
          import Input from '@/components/Input'

          然而,這樣做就失去了“導(dǎo)出桶”的優(yōu)勢。如何解決這個難題呢?很簡單,使用“命名導(dǎo)出”,也就是不使用“default”進行導(dǎo)出:

          import { Button, Icon, Input } from '@/components'

          與“導(dǎo)出默認”相關(guān)的另一個重要問題是重命名你導(dǎo)入的內(nèi)容的能力。我分享一個我職業(yè)生涯早期的真實案例。我接手了一個 React Native 項目,之前的開發(fā)者在所有東西中都使用了“導(dǎo)出默認”。有三個名為 “Login”、 “Register” 和 “ForgotPassword” 的屏幕。但是,這三個屏幕都是彼此的副本,只是做了一些細微的修改。問題是,在每個屏幕文件的末尾,都使用了一個 “export default Login”。這造成了混亂,因為路由文件正確地導(dǎo)入了:

          import Login from '../../screens/Login'
          import Register from '../../screens/Register'
          import ForgotPassword from '../../screens/ForgotPassword'

          // 在下面的路由中使用:

          {
            ResetPassword: { screen: ResetPassword },
            Login: { screen: LoginScreen },
            Register: { screen: RegisterScreen },
          }

          但是,當你打開屏幕文件時,它們都導(dǎo)出了相同的名稱:

          const login() {
            return <>login screen</>
          }
          export default Login
          const login() {
            return <>register screen</>
          }
          export default Login
          const login() {
            return <>forgot password screen</>
          }
          export default Login

          這導(dǎo)致了維護噩夢,出現(xiàn)了持續(xù)的混淆,需要格外小心才能避免錯誤。

          總而言之,強烈建議在大多數(shù)情況下使用“命名導(dǎo)出”,只有在絕對必要時才使用“導(dǎo)出默認”。有些情況下,例如 Next.js 路由和 React.lazy,可能需要使用“導(dǎo)出默認”。但是,在代碼清晰度和特定要求的遵守之間取得平衡至關(guān)重要。

          4. 正確的文件命名規(guī)范

          假設(shè)你有一個包含以下文件的 components 文件夾:

          --components:
          ----Button.tsx
          ----Icon.tsx
          ----Input.tsx

          現(xiàn)在,假設(shè)你想將這些組件的樣式、邏輯或類型分離到不同的文件中。你會如何命名這些文件呢?一個顯而易見的方法可能是:

          --components:
          ----Button.tsx
          ----Button.styles.css
          ----Icon.tsx
          ----Icon.styles.css
          ----Input.tsx
          ----Input.styles.css

          這種方法看起來有些混亂,而且難以理解,尤其是在你打算將組件進一步劃分為不同的文件(例如邏輯或類型)時。如何保持結(jié)構(gòu)井然有序呢?解決方案如下:

          --components:
          ----Button
          ------index.ts (exports everything necessary)
          ------types.ts
          ------styles.css
          ------utils.ts
          ------component.tsx
          ----Icon
          ------index.ts (exports everything necessary)
          ------types.ts
          ------styles.css
          ------utils.ts
          ------component.tsx
          ----Input
          ------index.ts (exports everything necessary)
          ------types.ts
          ------styles.css
          ------utils.ts
          ------component.tsx

          這種方法可以讓你輕松識別每個文件的用途,簡化了搜索所需內(nèi)容的過程。此外,如果你使用 Next.js 或類似框架,可以調(diào)整文件名來指示組件是用于客戶端還是服務(wù)器端。例如:

          --components:
          ----RandomComponent
          ------index.ts (exports everything necessary)
          ------types.ts
          ------styles.css
          ------utils.ts
          ------component.tsx
          ----RandomComponent2
          ------index.ts (exports everything necessary)
          ------types.ts
          ------styles.css
          ------utils.ts
          ------component.server.tsx

          這樣,你就可以非常容易地區(qū)分組件是用于客戶端還是服務(wù)器端,而無需打開代碼進行驗證。組織和標準化文件命名對于保持開發(fā)項目的清晰度和效率至關(guān)重要。

          5. 使用 ESLint 和 Prettier 規(guī)范代碼

          想象一下,你正在一個有 10 多個同事的項目中工作,每個人都從過去的經(jīng)驗中帶來了自己的編碼風格。這時,ESLint 和 Prettier 就派上用場了。它們在保持整個團隊的代碼一致性方面發(fā)揮著至關(guān)重要的作用。

          Prettier 就像代碼格式的“守門員”,確保每個人都遵循項目的代碼風格指南。例如,如果項目的標準規(guī)定使用雙引號,那么你就不能使用單引號,因為 Prettier 會自動將它們替換掉。此外,Prettier 還可以進行各種其他修復(fù)和格式化,例如代碼對齊、在語句末尾添加分號等等。你可以在官方文檔中查看具體的 Prettier 規(guī)則:Prettier 選項。

          另一方面,ESLint 對代碼強制執(zhí)行特定的規(guī)則,幫助維護一個一致的代碼庫。例如,它可以強制使用箭頭函數(shù)而不是普通函數(shù),確保 React 依賴項數(shù)組正確填寫,禁止使用 var 聲明而使用 let 和 const,以及應(yīng)用駝峰式命名約定等等。你可以在官方文檔中找到具體的 ESLint 規(guī)則:ESLint 規(guī)則。

          ESLint 和 Prettier 的結(jié)合使用有助于保持源代碼的一致性。如果沒有它們,每個開發(fā)者都可以遵循自己的風格,這可能會導(dǎo)致沖突,并且在未來維護代碼時會遇到困難。在項目中設(shè)置這些工具對于項目的長期維護至關(guān)重要,因為它有助于保持代碼的組織性,并易于理解。如果你還沒有使用 ESLint 和 Prettier,請認真考慮將它們納入你的工作流程,因為它們會對你的團隊和項目整體產(chǎn)生巨大的益處。

          6. Husky 和 Lint-Staged:加強代碼規(guī)范

          如果你已經(jīng)熟悉 ESLint 和 Prettier,那么你可能知道,在某些情況下,可以繞過這些工具定義的規(guī)則。為了確保遵守你制定的代碼指南并避免格式問題,強烈建議使用 Husky 和 Lint-Staged。

          這兩個工具在你的開發(fā)工作流程中發(fā)揮著至關(guān)重要的作用,允許你設(shè)置 ESLint 和 Prettier 在提交代碼之前運行。這意味著,只有在代碼符合你設(shè)置的規(guī)則的情況下,你才能提交代碼。你還可以配置這些工具,在將代碼推送到倉庫之前檢查代碼。

          此外,Husky 支持在提交或推送之前運行其他腳本或操作,這擴展了你的可能性,可以自動化驗證任務(wù),并確保代碼質(zhì)量。

          Husky 和 Lint-Staged 的另一個優(yōu)勢是它們與 GitHub 等代碼托管平臺的集成。這樣,你就可以在接受拉取請求之前設(shè)置自動測試和質(zhì)量檢查。這樣可以確保提交的代碼符合你制定的規(guī)則,最大限度地減少問題,并確保代碼一致性。

          這些工具對于防止開發(fā)者提交明顯存在問題的代碼至關(guān)重要,并確保代碼始終符合既定的指南。ESLint、Prettier、Husky 和 Lint-Staged 的組合是維護項目代碼質(zhì)量和標準化的一個非常有效的實踐。

          7. 使用自定義鉤子實現(xiàn)邏輯可復(fù)用

          在使用 React 時,我們經(jīng)常使用由 react-router-dom、Next.js 或 react-navigation (適用于 React Native) 等庫提供的導(dǎo)航鉤子。但是,這些通用的導(dǎo)航鉤子缺乏對應(yīng)用程序中特定頁面的了解,這會導(dǎo)致限制。一個有效的解決方案是創(chuàng)建自定義導(dǎo)航鉤子,這些鉤子了解應(yīng)用程序中的所有頁面,使它們之間的導(dǎo)航更加容易。

          以下是創(chuàng)建自定義導(dǎo)航鉤子的示例:

          import { useCallback } from 'react'
          import { useNavigate } from 'react-router-dom'
          import type { Routes } from '@/types'

          export const useRouter = () => {
            const navigate = useCallback((path: Routes) => goTo(path), [goTo])

            return { navigate }
          }

          這種方法可能一開始會讓人覺得有點復(fù)雜,但從長遠來看,它有幾個優(yōu)點。它簡化了鉤子的調(diào)用,并為函數(shù)提供了自動完成功能,使代碼更簡潔易懂。此外,它簡化了維護,因為如果將來需要更改導(dǎo)航庫,你只需要更改自定義鉤子,而不是更改所有使用導(dǎo)航鉤子的地方。

          創(chuàng)建自定義鉤子的這種思路可以應(yīng)用于應(yīng)用程序的其他方面,例如管理 cookie、本地存儲 (localStorage)、API 調(diào)用等等。這種方法允許你在項目的多個地方輕松地重用邏輯,從而提高模塊化,簡化代碼維護。

          8. 區(qū)分鉤子和實用函數(shù)

          理解創(chuàng)建鉤子和實用函數(shù)之間的區(qū)別至關(guān)重要,盡管開發(fā)者經(jīng)常混淆這兩個概念。為了說明這個區(qū)別,我將分享一個我在項目中早期使用過的、不太成熟的示例。

          在 Hooks 文件夾中:

          export const useFormat = () => {
            const formatHour = (date: number) => {
              return new Date(date).toLocaleTimeString('pt', { timeStyle'short' })
            }
            // 其他日期/時間格式化函數(shù)
            return { formatHour }
          }

          在這個示例中,我創(chuàng)建了一個實際上包含一個實用函數(shù)的鉤子。這種方法效率不高,因為每次使用它的組件渲染時都會創(chuàng)建一個新的鉤子,這可能會影響性能。此外,鉤子是特定于組件的,不容易在其他上下文中復(fù)用。

          正確的方法是在專門的目錄(例如“Utils”)中創(chuàng)建一個實用函數(shù):

          在 Utils 文件夾中:

          export const formatHour = (date: number) => {
            return new Date(date).toLocaleTimeString('pt', { timeStyle'short' })
          }

          在這種情況下,實用函數(shù)只創(chuàng)建一次,可以在項目的任何地方使用,與上下文無關(guān)。它不綁定到特定的組件,并且不會在每次渲染時都生成創(chuàng)建鉤子的開銷。

          根本區(qū)別在于,鉤子是一個沒有視覺部分的組件,它在 React 外部創(chuàng)建,并在特定組件內(nèi)調(diào)用,而實用函數(shù)只在 React 上下文之外創(chuàng)建一次,可以在任何地方使用。在鉤子和實用函數(shù)之間做出選擇應(yīng)該根據(jù)項目的具體需求和代碼復(fù)用考慮因素。

          9. 使用 useCallback 和 useMemo 進行性能優(yōu)化

          使用 useCallback、useMemo 以及不使用它們之間的區(qū)別,會對 React 應(yīng)用程序的性能優(yōu)化產(chǎn)生重大影響。本質(zhì)上,useCallback 用于記憶函數(shù),而 useMemo 用于記憶值。它們都旨在防止函數(shù)或值在每次組件渲染時被重新創(chuàng)建。

          這在 React 中尤為重要,因為 React 本身存在一個問題:在每次渲染時,函數(shù)和值都會被頻繁地重新創(chuàng)建。雖然 React 很高效,但這種頻繁的重新創(chuàng)建會導(dǎo)致子組件不必要地重新渲染,從而可能導(dǎo)致性能下降。需要注意的是,這是由于 React 的設(shè)計方式造成的,并非易事可以改變。

          解決這個問題的關(guān)鍵在于謹慎使用 useCallback 和 useMemo。它們可以幫助你避免頻繁地重新創(chuàng)建函數(shù)和值,從而提高應(yīng)用程序的性能。但是,必須謹慎使用它們,因為過度使用會適得其反,損害性能。每次使用 useCallback 或 useMemo 都涉及兩個操作:一個用于創(chuàng)建函數(shù)或值,另一個用于記憶它。此外,某些函數(shù)或值可能比記憶它們更容易重新創(chuàng)建。

          如果你已經(jīng)熟悉這個問題,你可能知道如何使用 useCallback 和 useMemo。但是,必須謹慎,因為過度使用會導(dǎo)致性能下降,甚至出現(xiàn)難以追蹤的錯誤(我保證你不會希望處理這種錯誤)。

          如果你不熟悉這個問題,強烈建議你閱讀各種有關(guān)該主題的文章,因為它是一個重大問題,有可能在 React 應(yīng)用程序中帶來性能挑戰(zhàn)和調(diào)試困難。

          10. 邏輯分離

          除了考慮鉤子和實用函數(shù)之間的區(qū)別之外,還必須盡可能地保持頁面的簡潔,并在可行的情況下分離邏輯。通過這樣做,你可以提高代碼的組織性和可維護性。以下是需要考慮的一些實踐:

          Toast 邏輯:  如果一個頁面需要顯示 Toast,最好創(chuàng)建一個單獨的組件和一個專門的函數(shù)來顯示這些 Toast。這樣,你就可以將邏輯與頁面的呈現(xiàn)分開。

          API 調(diào)用:  如果一個頁面進行 API 調(diào)用,請考慮使用 React Query 等庫,并將與這些調(diào)用相關(guān)的邏輯放在外部鉤子中。然后,頁面本身可以使用這個鉤子,使其更簡潔,專注于呈現(xiàn)。

          可復(fù)用組件:  對于可以在應(yīng)用程序的不同部分復(fù)用的組件,將它們放在全局組件目錄中。如果這樣組織起來變得混亂,你可以采用組件設(shè)計模式,例如原子設(shè)計。但是,請記住,軟件開發(fā)是動態(tài)的,隨時可能出現(xiàn)新的方法。評估這些方法對你特定情況的質(zhì)量和有效性。

          通過遵循這些代碼組織實踐,并秉持不斷學(xué)習的心態(tài),你可以提高工作效率和質(zhì)量,讓代碼更易于理解和維護。這反過來將進一步提高你作為開發(fā)者的價值。要不斷更新自己,并不斷探索新的方法,因為在這個充滿挑戰(zhàn)和活力無限的領(lǐng)域,持續(xù)學(xué)習是成功的關(guān)鍵


          • Node 社群

          •        


            我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習感興趣的話(后續(xù)有計劃也可以),我們可以一起進行Node.js相關(guān)的交流、學(xué)習、共建。下方加 考拉 好友回復(fù)「Node」即可。


          • 最后不要忘了點個贊再走噢


          瀏覽 106
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  熟女一区二区三区视频 | 操逼视频免费在线观看 | 天天干天天射天天舔 | 久久秘 一区二区三区四区 | 77777色婷婷 |