程序移植工具,從 Angular 移植到 React,代碼量減少了 20%

 2023-10-22 阅读 24 评论 0

摘要:【CSDN 編者按】從 Angular 移植到 React,代碼量減少了 20%?這是怎么回事呢,讓我們跟著作者來看看吧! 譯者 | 彎月 責編 | 宋彤彤 出品 | CSDN(ID:CSDNnews) 我開發了一款叫 Anita 的產品,當初選擇 Angular 是因為之

【CSDN 編者按】從 Angular 移植到 React,代碼量減少了 20%?這是怎么回事呢,讓我們跟著作者來看看吧!

譯者 | 彎月 責編 | 宋彤彤
出品 | CSDN(ID:CSDNnews)

我開發了一款叫 Anita 的產品,當初選擇 Angular 是因為之前我曾用它開發過表單生成器。然而,我擁有多年的 React 開發經驗,很快我就意識到 Angular 的開發速度非常慢。于是,我決定將代碼從 Angular 移植到 React。

程序移植工具。整個項目耗時不到 10 天,而且我是在業余時間內完成的。我認為這些付出非常值得,因為現在雖然代碼庫的功能完全相同,但代碼量減少了 20%。

下面,我們來看一些 VS Code Counter 生成的統計數據。

Angular 代碼庫的統計結果如下:

在這里插入圖片描述
不算 SCSS,Angular 應用程序的總代碼行數(包括模板)為 5,999。我將模板算作代碼,因為 Angular 遵循 MVVM(模型、視圖、視圖控制器)模式,這意味著模板會被編譯成 JavaScript 代碼。簡單介紹一下,在 Angular 中,模板是具有特殊語法的 HTML 塊,它們可以支持某些 Angular 功能,例如 for 循環。

移植后出血成功率大?React 代碼庫的統計結果如下:
在這里插入圖片描述
因此,React 應用程序的總代碼行數(包括模板)為 4,916。

我們來計算一下:

  • Angular 總代碼行數:5,999

  • React 總代碼行數:4,916

  • 移植編譯器?差異:-1,083 (-19.8443%)

這是一個巨大的提升。而實際上,Angular 的應用中使用了一個名為 Nebular 的 UI 庫,而在 React 中整個 UI 都是使用 TailwindCSS 定制的,也就是說在 React 中,很多 DOM 元素的目的都是渲染 Angular 中只需一行導入而生成的元素,如果將這個因素也考慮在內,則代碼量的減少就會更加顯著。

雖然每個人的統計結果會有所不同,但通過上述結果,我們可以看出代碼量的減少非常顯著,因為這兩個代碼庫都是由我一個人開發的,所以設計選擇和風格非常相似。我相信這個結果很好地表現出了 Angular 和 React 之間的差異。Angular 代碼庫更大,也更復雜;而 React 代碼庫則更小,也更簡單。

準備工作

為了將 Angular 應用轉變成全新的 React 應用,最快捷、最簡單的方式就是使用 create-react-app。

移植5c1,由于我們希望保留 Angular 應用的離線功能,而且想使用 TypeScript,因此創建 React 應用的命令為:


npx create-react-app anita-react--template cra-template-pwa-typescript

下面,我們運行 yarn start 來檢查一下結果:

在這里插入圖片描述
create-react-app 唯一的缺點是會添加很多新項目的代碼。我們來刪除沒用的代碼。

我們不需要 App 組件及其相關文件,另外 index.tsx 也可以清理掉:

 import React from 'react';import ReactDOM from 'react-dom';import './index.css';import * as serviceWorkerRegistration from'./serviceWorkerRegistration';ReactDOM.render(<React.StrictMode>"Hello World"</React.StrictMode>,document.getElementById('root'));serviceWorkerRegistration.register();

react nodejs、刪除如下文件:

  • App.csss

  • App.test.tsx

  • App.tsx

angular和react、在 Angular 項目中,所有靜態文件通常都在 app/src/assets 文件夾中。而在 React 中,assets 文件夾通常放在 public 文件夾中。所以,我們來移動一下 assets 文件夾。assets 文件夾保存在 src 中有點不太合理,因為它不包含源文件,而是提供給用戶的靜態文件,所以 React 更合理。

下面,我們來更新 public 文件夾中的 index.html 和 manifest.json,添加應用圖標、標題和描述。我們還可以刪除 create-react-app 生成的一些初始文件

  • public/favicon.ico

  • public/logo192.png

  • react webpack?public/logo512.png

下面,我們來看看代碼庫。

對路徑導入

在 Angular 項目中,我們使用絕對路徑來簡化導入,并使用了自定義前綴 @anita/client。

例如,我們使用這樣的語句:

react打包、import { MyModule } from'@anita/client/my.module

而不是:

import { AppModule } from'../../../my.module'

為此,我們需要正確配置 tsconfig.json 中的 paths。


"CompilerOptions": {..."paths": {"@anita/client/*": ["src/app/*"]}...
}

在開發 Angular 應用時,這種導入方法的優點是可以避免大量雜亂無章的導入。隨著代碼庫規模的增加,相對導入的路徑會變得很長。舉個例子,…/…/…/…/…/my.module.ts 就是一個過長的導航路徑。相較而言,@anita/client/my.module 則更加簡短,而且方便閱讀。

react.js框架。此外,無論文件位于項目樹結構的何處,它們的絕對路徑都是一樣的,因為絕對路徑是相對于代碼庫的根目錄而言的。

在將所有代碼移植到 React 的過程中,這種導入策略非常方便,因為我們可以將所有代碼轉移到新項目中,然后使用 replace all 一次性更新所有導入。

因此,React 應用也必須使用絕對路徑。

在 React 中,我們不能在 tsconfig.json 中使用 paths。然而,我們可以使用baseUrl,它允許我們根據絕對路徑(相對于根目錄而言)導入文件。我們的這個項目選擇了 src 文件夾:


"CompilerOptions": {..."baseUrl": "src"...
}

java react,有了這個配置,我們就可以根據絕對路徑導入文件了。所以,./src/app/app.component 就變成了 app/app.component。

這樣,在移植代碼時,我們可以簡單地將所有 @anita/client 替換為 app,只要保持文件夾層次結構不變,所有導入都會順利完成。

下面,我們來看看項目結構。

項目結構

為了簡化從 Angular 到 React 的轉換,我們保留了類似的文件夾層次結構。這樣,我們就可以將所有代碼直接放入 React 項目中了。

Angular 應用的結構如下:

  • src/app/

    data:包含數據模型。

    libs:包含非特定于 Angular 的庫。

    ng-services:包含 Angular 服務。

    ui:包含 Angular UI 元素,以及 UI 所需的一些 Angular 服務和流水線。

React 的結構則更簡單:

  • src/app/

    anita-routes:包含應用的路由。因為這些不再是 Angular 的服務,所以我們可以將它們放在這個文件夾內。

    data:包含數據模型,與 Angular 應用相同。

    libs:包含 Angular 應用中使用的庫,可以直接移植到 React,或者做少量修改。

    ui-react-components:包含 React 組件。

設置UI:從 Nebular 到 TailwindCSS

在構建 Angular 的 UI 時,我使用了 Nebular(一個可定制的 Angular UI 庫)。Nebular 是一個很棒的工具,但僅適用于 Angular,在 React 中使用就有點大材小用了。

我相信對于我的這個項目,TailwindCSS 是更好的選擇。這是一個優秀的 CSS 框架,其中包含 flex、pt-4、text-center 和 rotate-90 等類,可以直接在 HTML 中組合使用。

在 React 中安裝 TailwindCSS 也非常簡單,具體的說明請參見官方文檔(https://tailwindcss.com/docs/guides/create-react-app)。

我的應用的網站首頁使用了 TailwindCSS,因此可以在整個應用中采用相同的風格。我們需要做的是在 tailwind.config.js 中定義項目使用的幾種顏色:


const colors =require('tailwindcss/colors')

module.exports = {// Purges the final stylesheet of unused/un-optimized selectors, keepingonly what is used in the app.purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],darkMode: false,theme: {colors: {transparent: 'transparent',current: 'currentColor',black: colors.black,white: colors.white,rose: colors.rose,pink: colors.pink,fuchsia: colors.fuchsia,purple: colors.purple,violet: colors.violet,indigo: colors.indigo,blue: colors.blue,'prussian-blue': {DEFAULT: '#002346','50': '#2D96FF','100': '#1389FF','200': '#006FDF','300': '#0056AC','400': '#003C79','500': '#002346','600': '#002346','700': '#000f20','800': '#000e1f','900': '#000d1b'},sky: colors.sky,cyan: colors.cyan,teal: colors.teal,emerald: colors.emerald,green: colors.green,lime: colors.lime,yellow: colors.yellow,amber: colors.amber,orange: colors.orange,red: colors.red,warmGray: colors.warmGray,trueGray: colors.trueGray,gray: colors.gray,coolGray: colors.coolGray,blueGray: colors.blueGray}},variants: {extend: {},},plugins: [require('@tailwindcss/forms')],
}

下面,我們用 TailwindCSS 創建一些布局。由于我的應用的主界面是一個管理面板,所以我們就從這里著手。

讓我們在 index.tsx 中實現一個非常基本的管理面板:


ReactDOM.render(<React.StrictMode><div className="bg-prussian-blue-400 text-gray-100 flexjustify-between"><div className="flex-grow relative flex items-center lg:w-autolg:static pl-5"><a className="text-lg font-bold leading-relaxed inline-blockmr-4 py-2 whitespace-no-wrap uppercase text-white" href="/"><img src="/assets/logo/logo_square.svg" style={{ height:'30px', width: 'auto' }} alt="Anita" /></a><a className="text-md font-bold leading-relaxed inline-blockmr-4 py-2 whitespace-no-wrap uppercase text-white" href="/">Anita</a></div><button className="mobile-menu-button p-4 focus:outline-nonefocus:bg-gray-700"><svg className="h-5 w-5"xmlns="http://www.w3.org/2000/svg" fill="none"viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round"strokeWidth="2" d="M4 6h16M4 12h16M4 18h16" /></svg></button></div><div className="relative min-h-screen md:flex"><div className="sidebar bg-gray-200 text-prussian-blue-500 w-64space-y-6 py-7 px-2 absolute inset-y-0 left-0 transform -translate-x-fullmd:relative md:translate-x-0 transition duration-200 ease-in-out"><nav><a href="https://anita-app.com" className="blockpy-2.5 px-4 rounded transition duration-200 hover:bg-prussian-blue-600hover:text-white">Menu item 1</a><a href="https://anita-app.com" className="blockpy-2.5 px-4 rounded transition duration-200 hover:bg-prussian-blue-600hover:text-white">Menu item 2</a><ahref="https://anita-app.com" className="block py-2.5 px-4rounded transition duration-200 hover:bg-prussian-blue-600hover:text-white">Menu item 3</a><a href="https://anita-app.com" className="blockpy-2.5 px-4 rounded transition duration-200 hover:bg-prussian-blue-600hover:text-white">Menu item 4</a></nav></div><div className="flex-1 p-10">Content</div></div></React.StrictMode>,document.getElementById('root')
);

下面,我們來測試一下 TailwindCSS,以及頁面布局:

在這里插入圖片描述
很好。下面我們來添加一些組件。

我們可以將頁面劃分成三個區域:

  • Header

  • Sidebar

  • Content

每個區域都是一個 React 組件,并且可以導入到容器組件 AdminLayout 中:


export const AdminLayout = () => (<div><Header /><div className="relative admin-container md:flex"><Sidebar><nav><a href="https://anita-app.com" className="blockpy-2.5 px-4 rounded transition duration-200 hover:bg-prussian-blue-600hover:text-white">Menu item 1</a><a href="https://anita-app.com" className="blockpy-2.5 px-4 rounded transition duration-200 hover:bg-prussian-blue-600hover:text-white">Menu item 2</a><a href="https://anita-app.com" className="blockpy-2.5 px-4 rounded transition duration-200 hover:bg-prussian-blue-600 hover:text-white">Menu item 3</a><a href="https://anita-app.com" className="blockpy-2.5 px-4 rounded transition duration-200 hover:bg-prussian-blue-600hover:text-white">Menu item 4</a></nav></Sidebar><Content>Hello world!<br /></Content></div></div>
);

占位文本暫時保留,稍后再添加實際的內容。稍后我們還將實現側面工具欄的開閉功能。下面,我們來處理狀態管理。

將狀態管理從 NgRx 移植到 Redux

在 Angular 應用中,我使用了 NgRx,這個庫是受 Redux 的啟發而為 Angular 應用開發的反應式狀態管理。我決定使用 NgRx 也是因為它與 Redux 非常相似。

因此,將狀態管理的代碼從 Angular 移植到 React 非常方便,我們只需將調用 NgRx store 的代碼改成調用 Redux 即可。但一般這種修改并不容易,因為 Angular 中的 NgRx 是作為單例服務加載的。單例服務必須由 Angular 初始化,因此它們的實例只能在 Angular 元素中使用,比如服務和組件等。

我根據多年的經驗,想出了一個奇妙的方法來解決這個問題。我們可以在一個自定義服務中初始化 NgRx store,并將初始化后的 store 的引用傳遞給一個常量,而該常量可以導入到 Angular 應用的任何位置。

Angular 服務必須使用 @Injectable 裝飾器在類中初始化,如下所示:

export const stateData = {ngRxStore: undefined
};@Injectable({providedIn: 'root'
})
export class StateDataService {constructor(private store: Store<ReducerTypes>
) {this.initRedux();}// This is the "dirty" trickpublic initRedux(): void {stateData.ngRxStore = this.store;}
}

此處有兩點需要注意:

  • private store:Store 會根據管理 Angular 單例服務的邏輯初始化 NgRx。

  • stateData 是一個對象,用于保存初始化后的 NgRxstore。

在 JavaScript 中,通過 “=” 將一個對象分配給另一個變量不會創建新對象。運算符 “=” 會將變量賦值為內存中已有對象的引用。這就是我們使用stateData.ngRxStore = this.store 的原因。我們將 store 賦給 stateData.ngRxStore。由于這只是對原對象的引用,所以訪問 stateData.ngRxStore 的屬性,比如 dispatch,實際上就是訪問由 Angular 初始化的 NgRx 單例服務。

接下來,我們可以任意文件中導入 stateData,并通過它來訪問 store,而且無需初始化。我們無需在構造函數中注入 NgRx store,就可以從應用的任意置訪問 store。如此一來,大部分代碼都可以保持普通的 TypeScript/JavaScript,而不是 Angular 服務。我的應用中大部分代碼都在 libs 文件夾中,而非 ng-services 文件夾中。

根據以往的經驗,這個技巧非常有效,在這里使用也非常方便,因為我們可以將所有非 Angular 的代碼轉移到 React。在 React 應用中,我們需要做的就是導入 Redux store,并將 stateData.ngRxStore 替換為這個 store。例如,src/app/libs/project-helpers/project-handlers中的 CurrentProjectSetter 類,我們可以將 stateData.ngRxStore.dispatch 替換成 store.dispatch。其余代碼保持不變。

然而,首先我們必須在 React 應用中初始化 Redux。下面,我們先在 React 項目中添加 redux 和react-redux:


yarn add react-redux redux

然后輸入:


yarn add @types/react-redux --dev

NgRx 到 Redux reducer 的轉換很簡單:

const projectState: SystemData =undefined;
const _projectReducer =createReducer(projectState,on(REDUCER_ACTIONS.setCurrentProject, (state, data) => {return data.payload;})
);
export function projectReducer(state:SystemData, action: typeof REDUCER_ACTIONS.setCurrentProject): any {return _projectReducer(state, action);
}

得到的 React 代碼如下:


const projectState: SystemData =undefined;
export const projectReducer = (state:SystemData = projectState, action: Action<REDUX_ACTIONS>): SystemData=> {switch (action.type) {case REDUX_ACTIONS.setCurrentProject:return action.payloaddefault:return state;}
}

在移植完所有的 reducer,我們就可以創建 react-redux store了:

const REDUCERS = {project: projectReducer,projects: projectsReducer,sectionsForChildOfSelector: sectionsForChildOfSelectorReducer
};
const combinedReducers =combineReducers(REDUCERS)
export const store =createStore(combinedReducers);

接下來,我們就可以在 React 應用中引用導出的常量 store 了。

路由

在 Angular 中,我們使用 @angular/router 來處理路由:


export const routes: Routes = [{ path: 'private', redirectTo: 'private/projects/list', pathMatch:'full' },{ path: 'private', children:[{path: '', component:AdminComponent, children: [{ path: 'projects', redirectTo:'projects/list', pathMatch: 'full' },{ path: 'projects', children: [{ path: 'list', component:ProjectsListComponent, canActivate: [ProjectsGuardService] },...]},{ path: 'project', redirectTo:'projects/list', pathMatch: 'full' },{ path: 'project', canActivate:[ProjectGuardService], children: [{ path: '', redirectTo:'projects/list', pathMatch: 'full' },{ path:`:${URL_PARAMS.projectId}`, redirectTo: ':projectId/info', pathMatch: 'full' },{ path:`:${URL_PARAMS.projectId}/info`, component: ProjectInfoComponent },...]}]}]},{ path: '', redirectTo: 'private/projects/list', pathMatch: 'full' },{ path: '**', redirectTo: 'private/projects/list', pathMatch: 'full' }];

在 React 中,我們使用 react-router 來處理路由。目前 React Router 是最流行的路由庫。

首先,我們需要安裝 react-router。

yarn add react-router-dom

由于我的應用托管在 GitHub Pages 上,因此我們需要使用 HashRouter(不是 BrowserRouter)。在這種方式下,路由的前綴都是 “#”。

由于所有視圖都在同一個地方渲染,AdminLayout 組件的 content 區域就是我們渲染路由的地方。

為了方便閱讀,所有路由都在一個單獨的 React 組件 AnitaRoutes 中定義。


import { HashRouter as Router } from'react-router-dom';
export const AdminLayout = () => (<Router><Header /><div className="relative admin-container flex"><Sidebar><SidebarMenu /></Sidebar><Content><AnitaRoutes /></Content></div></Router>
);

AnitaRoutes 中包含所有的路由定義:


import { Navigate, Route, Routes } from'react-router-dom';
export const AnitaRoutes = () => (<Routes><Route path={ANITA_URLS.projectsList} element={<ProjectsList/>} /><Route path={ANITA_URLS.projectAdd} element={<AddEditProject/>} /><Route path={ANITA_URLS.projectEdit} element={<AddEditProject/>} /><Route path={ANITA_URLS.projectsNone} element={<ProjectsNone/>} /><Route path={ANITA_URLS.projectDetails} element={<ProjectDetails/>} /><Route path={ANITA_URLS.projectSectionElesList}element={<SectionElementsList />} /><Route path={ANITA_URLS.projectSectionEleDetails}element={<SectionElementDetails />} /><Route path={ANITA_URLS.projectSectionAddEle}element={<AddEditSectionElement />} /><Route path={ANITA_URLS.projectSectionEditEle}element={<AddEditSectionElement />} /><Route path="*" element={<Navigateto={ANITA_URLS.projectsList} />}/></Routes>
)

請注意,所有的路由都定義在常量 ANITA_URL 中。這是因為我們希望盡量保持代碼整潔,而且也希望盡量簡化路由的定義。


export const ANITA_URLS = {
// PROJECTS
projectsNone: '/projects/none',
projectsList: '/projects/list',
projectAdd:`/projects/${EDITOR_MODE.add}`,
projectEdit:`/projects/${EDITOR_MODE.edit}/:${URL_PARAMS.projectId}`,
// PROJECT
projectDetails:`/project/:${URL_PARAMS.projectId}/info`,
projectSectionElesList:`/project/:${URL_PARAMS.projectId}/list/:${URL_PARAMS.sectionId}`,
projectSectionAddEle:`/project/:${URL_PARAMS.projectId}/:${URL_PARAMS.sectionId}/${EDITOR_MODE.add}`,
projectSectionEditEle:`/project/:${URL_PARAMS.projectId}/:${URL_PARAMS.sectionId}/${EDITOR_MODE.edit}/:${URL_PARAMS.elementId}`,
projectSectionEleDetails:`/project/:${URL_PARAMS.projectId}/:${URL_PARAMS.sectionId}/details/:${URL_PARAMS.elementId}`,

如你所見,有些路由是在其他常量 URL_PARAMS 和 EDITOR_MODE 中定義的。這種方式可以避免輸入錯誤,并讓整個應用中的所有路由都保持一致。

這兩個常量非常簡單:


export const URL_PARAMS = {projectId: 'projectId',sectionId: 'sectionId',elementId: 'elementId',parentId = 'parentId'
}export const EDITOR_MODE = {add: 'add',edit: 'edit',
}

舉個例子,路由 projectSectionEditEle:


/project/:${URL_PARAMS.projectId}/:${URL_PARAMS.sectionId}/${EDITOR_MODE.edit}/:${URL_PARAMS.elementId}

轉換成了:


/project/:projectId/:sectionId/edit/:elementId

下面,我們只需生成路由的鏈接。我們可以使用一個函數來填充路由的所有參數。指定一個 URL,以及一組參數和值,該函數就能夠自動填充所有的參數,并生成正確的 URL :


export function urlParamFiller(url:string, paramsToFill: Array<{ name: URL_PARAMS; value: string }>): string{let result = url;paramsToFill.forEach(params => {result = result.replace(new RegExp(`:${params.name}`, 'g'),params.value) });return result;}

我們不需要擔心參數的順序,因為 urlParamFiller 函數會替換路由中出現的所有參數。

我們可以利用該函數生成路由的鏈接,例如生成指向項目詳細信息頁面的鏈接:


<Linkto={urlParamFiller(ANITA_URLS.projectDetails, [{ name:URL_PARAMS.projectId, value: project.id }])}className="px-4 py-3 text-white inline-flex items-centerleading-none text-sm bg-prussian-blue-400 hover:bg-prussian-blue-500rounded"><i className="bi-info-circle mr-2"></i>Projectdetails
</Link>

這個例子也表明使用 React 構建應用比 Angular 更加容易。我們的路由只是常量連接的字符串,可通過上述函數生成鏈接。為了避免人為錯誤,我們使用 urlParamFiller 函數填充路由的參數。雖然有需求的話,可以使用嵌套路由,但此處我們不需要指定路由的層次結構。我們可以簡單地使用連接字符串,將生成完整的 URL 的任務委托給 urlParamFiller,就可以導航到任意想去的頁面了。

構建用戶界面

不幸的是,UI 的構建從 Angular 移植到 React 就沒有那么簡單了,因為我們使用的 UI 庫有很大的不同。

在 Angular 中,我們使用了 Nebular,這是一個基于 Bootstrap 4 的 UI 庫,包含大量預定義的 UI 組件。而在 React 中,我們選擇使用 TailwindCSS,其中提供了很多組件可用于創建漂亮的 UI,但這個庫不附帶任何預定義組件。所以,我們必須手動構建。

簡單來說,我們需要從零開始構建整個應用的 UI。

在這個過程中,我們需要注意一個問題:我們不需要從 Angular 組件中借用很多代碼。有一個非常重要的最佳實踐:盡可能將 UI 和代碼分開。因此在創建新的 UI 組件時,我們應該盡量將邏輯處理保留在應用的代碼中,而不是 UI 組件中。無論是 Angular 還是 React,我都將這些代碼都保存到了文件夾 src/app/libs 中。我們可以在組件中導入運行應用運行所需的 libs 類和函數。

比一下 Angular 和 React,我們還會注意到 Angular 版本更為復雜,因為它的樣板代碼更多。

下面,我們來看一個簡單的 Angular 組件,AddBtnComponent,它由三個文件組成:

  1. add-btn.component.ts:組件本身。
  2. add-btn.component.html:組件的HTML模板。
  3. add-btn.component.scss:組件的樣式。

add-btn.component.ts

 import ...@Component({selector: 'app-add-btn',templateUrl: './add-btn.component.html',styleUrls: ['./add-btn.component.scss']
})
export class AddBtnComponent {@Input()public url: string;@Input()public icon = 'plus-outline';@Input()public element: SectionElement;constructor(private router: Router) { }public navigate(): void {this.router.navigateByUrl(this.url, {state: { element: this.element }});}}

add-btn.component.html


<button *ngIf="url"nbButton shape="round" status="primary"size="giant" class="position-absolute shadow"(click)="navigate()"><nb-icon [icon]="icon"></nb-icon> <!-- Nebularicon element -->
</button>

add-btn.component.scss:略。

而在 React 中只需要一個文件 add-edit-element-button.component.tsx,且只有 6 行代碼:


export const AddEditElementButton = ({icon, url }) => (<Link to={url} className="absolute bottom-5 right-7 md:bottom-7md:right-10 bg-prussian-blue-400 text-white text-xl shadow-xl rounded-3xl h-14w-14 flex items-center justify-center"><i className={icon}></i></Link>)

由于 React 16.8 引入了 Hooks,因此樣板代碼幾乎為零。

你可以根據自己的喜好,選擇喜歡的框架。根據我的經驗,使用 React 編寫應用更快,也更容易維護。

最終的結果

從Angular 移植到 React 是一次非常有趣的嘗試,也是一次很棒的學習經歷。

下面是最終得到的應用的一些截圖:

1.初始頁面,項目還未建立:
在這里插入圖片描述
2.示例項目:
在這里插入圖片描述
為了方便比較,我們來看看 Angular。

1.初始頁面,項目還未建立:

在這里插入圖片描述
2.示例項目:

在這里插入圖片描述
原文地址:https://anita-app.com/blog/articles/porting-anita-from-angular-to-react-resulted-in-20-less-code.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/1/159185.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息