比精讀:Vue.js 與 React 的核心差異解析)
教程知識(shí)庫(kù)【免費(fèi)下載鏈接】tech-interview-for-developer ?? ??? ?? ?? ?? ?? ???? 項(xiàng)目地址https://gitcode.com/GitHub_Trending/te/tech-interview-for-developer點(diǎn)擊查看免費(fèi)下載本篇技術(shù)指南以倉(cāng)庫(kù)中的 Web/Vue.js? React? ??.md 為骨架系統(tǒng)梳理 Vue.js 與 React 在開發(fā) CLI、樣式組織方式、數(shù)據(jù)更新機(jī)制三個(gè)維度上的核心差異并結(jié)合倉(cāng)庫(kù)內(nèi) Vue 生命周期、React Hook、兩框架與 Spring Boot 集成等筆記進(jìn)行縱深展開。讀完本文你可以直接掌握兩套框架在工程初始化、狀態(tài)變更寫法與響應(yīng)式原理上的關(guān)鍵區(qū)別為技術(shù)面試中的框架對(duì)比題與真實(shí)項(xiàng)目選型建立清晰的回答脈絡(luò)。為什么面試與選型都要問 Vue.js 與 React 的差異Vue.js 與 React 是當(dāng)前前端開發(fā)中使用最廣泛的兩大視圖層框架。在 README.md 所收錄的 Web 知識(shí)體系中本倉(cāng)庫(kù)將 Vue.js vs React 作為獨(dú)立的知識(shí)點(diǎn)收錄見根 README 的 Web 目錄并在 Web/README.md 中把 Vue 的生命周期、Vue CLI Spring Boot 集成與 React 的 Hook、Fragment、Spring Boot 集成 等筆記分別歸檔。因此圍繞兩者差異展開的知識(shí)點(diǎn)實(shí)際上是理解兩大框架工程化與響應(yīng)式設(shè)計(jì)的最佳切入點(diǎn)。原文檔主要從三個(gè)角度對(duì)比二者開發(fā) CLIvue-cli vs create-react-app、CSS 文件組織方式、數(shù)據(jù)變異data mutation機(jī)制。本文按此骨架逐節(jié)展開并補(bǔ)充倉(cāng)庫(kù)內(nèi)的源碼級(jí)筆記佐證。一、開發(fā) CLIvue-cli 與 create-react-app原文檔指出兩框架分別擁有官方推薦的腳手架工具Vue.js使用vue-cliReact使用create-react-app1.1 Vue 側(cè)Vue CLI 的實(shí)際使用倉(cāng)庫(kù)的 Web/Vue/Vue CLI Spring Boot ???? ?? ????.md 記錄了 Vue CLI 的完整初始化流程$ npm i -g vue/cli # 安裝 Vue CLI $ npm i -g vue/cli-init # 提供 vue init拉取 2.x 模板的兼容包 $ vue init webpack frontend # 在 Spring Boot 根目錄下創(chuàng)建名為 frontend 的 Vue 項(xiàng)目文檔同時(shí)說明vue init過程中會(huì)交互式詢問 Project name、Project description、Author 等元信息并讓開發(fā)者選擇 Vue build 模式standalone、是否安裝 vue-router、是否啟用 ESLintpreset 可選 Standard以及是否配置測(cè)試部分。腳手架完成后項(xiàng)目根目錄會(huì)生成一個(gè)獨(dú)立的frontend前端工程。值得注意的工程化細(xì)節(jié)Vue CLI 項(xiàng)目通過config/index.js中的build配置控制 webpack 打包輸出位置。在與 Spring Boot 集成時(shí)需要把輸出目錄指到src/main/resources/static使 Spring Boot 自動(dòng)配置能直接識(shí)別index.html與 css、img、javascript 等靜態(tài)資源。這是腳手架初始化之外很容易踩坑的一步。1.2 React 側(cè)create-react-app 與手動(dòng) webpack 組合React 生態(tài)的官方初始化工具是create-react-app。倉(cāng)庫(kù)的 Web/React/React Spring Boot ???? ?? ????.md 提到create-react-app 一次安裝即可完成依賴配置同時(shí)該文檔示范了不依賴 CRA 的手動(dòng)搭建路線便于理解底層構(gòu)成$ npm init # 生成 package.json $ npm i react react-dom # 運(yùn)行時(shí)依賴 $ npm i babel/core babel/preset-env babel/preset-react babel-loader css-loader style-loader webpack webpack-cli -D # 構(gòu)建依賴隨后通過webpack.config.js配置入口src/main/jsx、babel-loader 的 presetsbabel/preset-envbabel/preset-react以及 css/style loader并把打包產(chǎn)物輸出到src/main/webapp/js/react/[name].bundle.jsvar path require(path); module.exports { context: path.resolve(__dirname, src/main/jsx), entry: { main: ./MainPage.jsx, page1: ./Page1Page.jsx }, devtool: sourcemaps, cache: true, output: { path: __dirname, filename: ./src/main/webapp/js/react/[name].bundle.js }, mode: none, module: { rules: [ { test: /\.jsx?$/, exclude: /(node_modules)/, use: { loader: babel-loader, options: { presets: [ babel/preset-env, babel/preset-react ] } } }, { test: /\.css$/, use: [ style-loader, css-loader ] } ] } };開發(fā)時(shí)通過node_modules\.bin\webpack --watch -d開啟增量構(gòu)建-d為開發(fā)模式、-p為生產(chǎn)模式并可把start、watch命令注冊(cè)進(jìn)package.json的scripts中簡(jiǎn)化操作。1.3 小結(jié)維度Vue.jsReact官方腳手架vue-clicreate-react-app初始化方式vue init/vue create交互式生成npx create-react-app一條命令生成與 Spring Boot 集成webpack 輸出到src/main/resources/staticwebpack 輸出到src/main/webapp/js/react由 JSP 引用 bundle.js兩者都是模板 webpack 構(gòu)建思路區(qū)別在于 Vue CLI 把路由vue-router、狀態(tài)管理vuex、ESLint 等選項(xiàng)內(nèi)置到交互流程中React 手動(dòng)方案則需要自行組合 webpack、babel preset-react 與 entry 配置。二、CSS 的組織方式組件內(nèi)樣式 vs 獨(dú)立樣式文件原文檔指出二者在樣式組織上的顯著差異Vue.js沒有獨(dú)立的 CSS 文件style直接在組件文件內(nèi)部定義React存在獨(dú)立的 CSS 文件通過文件方式應(yīng)用樣式2.1 Vue 的單文件組件SFC模型Vue 采用單文件組件Single File Component組織代碼模板、邏輯與樣式同處一個(gè).vue文件中template定義結(jié)構(gòu)、script定義邏輯、style定義樣式。這種樣式內(nèi)聚于組件的寫法讓組件自包含程度更高配合 scoped 樣式即可實(shí)現(xiàn)局部作用域隔離不需要額外管理全局 CSS 文件。2.2 React 的獨(dú)立樣式文件模型React 組件尤其是函數(shù)組件通常只包含 JS/JSX 邏輯樣式以獨(dú)立 CSS 文件存在并在 JSX 中通過import引入。倉(cāng)庫(kù)的 React Spring Boot 集成文檔展示了這一模式頁(yè)面組件通過import ../webapp/css/custom.css;引入樣式文件再以className引用其中的樣式類import ../webapp/css/custom.css; import React from react; import ReactDOM from react-dom; class MainPage extends React.Component { render() { return div classNamemainno4gift ?? ???/div; } } ReactDOM.render(MainPage/, document.getElementById(root));對(duì)應(yīng)的custom.css中以普通類選擇器定義樣式.main { font-size: 24px; border-bottom: solid 1px black; } .page1 { font-size: 14px; background-color: yellow; }文檔也強(qiáng)調(diào)CSS 應(yīng)用方式并非只有 import 這一種CSS Modules、styled-components 等方案都屬于 React 生態(tài)的樣式擴(kuò)展。需要說明的是這一差異描述的是兩框架的主流默認(rèn)組織方式Vue 的 SFC 以style內(nèi)聯(lián)為主React 以獨(dú)立樣式文件為主二者并不絕對(duì)排斥其他方案。2.3 相關(guān)的結(jié)構(gòu)差異JSX 的單根節(jié)點(diǎn)約束React 的樣式與結(jié)構(gòu)差異還延伸到 JSX 語(yǔ)法約束上。倉(cāng)庫(kù)的 Web/React/React Fragment.md 指出JSX 文件規(guī)則要求return時(shí)必須用一個(gè)標(biāo)簽包裹所有元素。若把多個(gè)td塞進(jìn)div返回會(huì)破壞table的合法 DOM 結(jié)構(gòu)div不能出現(xiàn)在tr內(nèi)。此時(shí)應(yīng)使用Fragment或簡(jiǎn)寫包裹因?yàn)?Fragment 不會(huì)在 DOM 樹中額外生成節(jié)點(diǎn)import { Component } from React class Columns extends Component { render() { return ( Fragment tdHello/td tdWorld/td /Fragment ); } }三、數(shù)據(jù)更新機(jī)制響應(yīng)式自動(dòng)更新 vs setState 顯式提交這是原文檔的核心對(duì)比點(diǎn)也是面試中的高頻考點(diǎn)。原文檔給出的對(duì)比// name: kim 的值要改成 lee // Vue.js : this.name lee // React : this.setState({name:lee})原文檔同時(shí)點(diǎn)明關(guān)鍵結(jié)論Vue 在更新 data 時(shí)會(huì)自動(dòng)把 setState 式的更新邏輯依賴追蹤 重新渲染調(diào)度結(jié)合進(jìn)去開發(fā)者無(wú)需手動(dòng)觸發(fā)而 React 需要顯式調(diào)用setState。3.1 Vue 的響應(yīng)式 dataVue 中數(shù)據(jù)必須掛在data對(duì)象上組件選項(xiàng)式寫法中才能成為響應(yīng)式數(shù)據(jù)必須先創(chuàng)建 data 對(duì)象之后才能對(duì) data 進(jìn)行更新對(duì)data屬性直接賦值即可觸發(fā)視圖更新this.name lee框架內(nèi)部會(huì)為每個(gè)屬性建立依賴收集與派發(fā)更新的機(jī)制更新 data 時(shí)自動(dòng)結(jié)合 setState 行為即賦值后自動(dòng)完成重渲染調(diào)度。3.2 React 的 state 與 setStateReact 中組件狀態(tài)存放于state更新必須通過setState先創(chuàng)建 state 對(duì)象類組件this.state {...}函數(shù)組件useState初始化更新時(shí)比 Vue 多一步顯式提交this.setState({name:lee})setState是異步批處理的它通知 React 狀態(tài)已變更需要重新渲染不能直接通過賦值修改this.state來觸發(fā)更新。3.3 函數(shù)組件時(shí)代React Hook 的狀態(tài)寫法倉(cāng)庫(kù)的 Web/React/React Hook.md 記錄了 React 16.8 引入 Hook 的動(dòng)機(jī)類組件存在狀態(tài)邏輯難以復(fù)用、代碼復(fù)雜度上升、無(wú)關(guān)邏輯相互混雜三大痛點(diǎn)。Hook 讓函數(shù)組件也能擁有 state 與生命周期能力const [posts, setPosts] useState([]); // 解構(gòu)賦值() 內(nèi)為初始值狀態(tài)變更時(shí)調(diào)用以set命名的更新函數(shù)如setPosts(newPosts)這與類組件的setState一脈相承只是粒度更細(xì)。useEffect則在組件每次渲染后執(zhí)行副作用相當(dāng)于類組件componentDidMount()與componentDidUpdate()的合體useEffect(() { console.log(??? ??); console.log(posts); });當(dāng)posts變化觸發(fā)重渲染時(shí)useEffect會(huì)再次執(zhí)行??梢?React 無(wú)論是類組件還是函數(shù)組件顯式觸發(fā)更新這一思想始終貫穿。3.4 延伸Vue 中的 computed 與 watchVue 在直接賦值之外還提供聲明式與命令式兩種數(shù)據(jù)派生手段倉(cāng)庫(kù)的 Web/Vue/Vue.js ?????? ????.md 給出了完整示例// computed聲明式基于依賴自動(dòng)緩存計(jì)算 new Vue({ el: #demo, data: { firstName: Foo, lastName: Bar }, computed: { fullName: function () { return this.firstName this.lastName } } })// watch命令式監(jiān)聽指定數(shù)據(jù)變化后執(zhí)行回調(diào) new Vue({ el: #demo, data: { firstName: Foo, lastName: Bar, fullName: Foo Bar }, watch: { firstName: function (val) { this.fullName val this.lastName }, lastName: function (val) { this.fullName this.firstName val } } })該文檔給出的選型結(jié)論非常實(shí)用computed 是聲明式、watch 是命令式watch 適合API 調(diào)用等異步結(jié)果返回前的中間狀態(tài)設(shè)置或耗時(shí)計(jì)算而大多數(shù)場(chǎng)景優(yōu)先使用聲明式的 computed。另外需要注意像Date.now()這種沒有響應(yīng)式依賴的 computed 屬性不會(huì)自動(dòng)更新——若每次調(diào)用都要拿到當(dāng)前時(shí)間應(yīng)改用 methods。四、生命周期與渲染模型的差異兩框架不僅更新寫法不同生命周期模型也各有側(cè)重這一節(jié)同樣來自倉(cāng)庫(kù)的 Vue 生命周期筆記。4.1 Vue 的四階段生命周期Vue 生命周期分為四大階段Creation初始化、Mounting掛載、Updating更新、Destruction銷毀。Creation組件初始化階段所有鉤子最早執(zhí)行此時(shí)組件尚未插入 DOM且該階段鉤子在服務(wù)端渲染SSR中同樣受支持因此客戶端與服務(wù)端渲染都要做的事應(yīng)放在此階段。beforeCreate最先執(zhí)行data 與事件尚未設(shè)置無(wú)法訪問createddata、事件已激活可訪問但模板與 virtual DOM 尚未掛載/渲染。MountingDOM 插入階段初始渲染前可訪問組件組件初期需要設(shè)置的數(shù)據(jù)更適合在created中處理。beforeMount模板或渲染函數(shù)編譯完成后、首次渲染發(fā)生前執(zhí)行使用頻率低mounted組件、模板、渲染后的 DOM 均可訪問所有畫面渲染完成后執(zhí)行。Updating響應(yīng)式屬性變化或重新渲染時(shí)觸發(fā)可用于調(diào)試時(shí)感知組件何時(shí)被重渲染。beforeUpdate數(shù)據(jù)變更、更新周期啟動(dòng)、DOM 重渲染與 patch 之前updated重新渲染完成后執(zhí)行可進(jìn)行 DOM 依賴運(yùn)算。Destruction解構(gòu)階段。beforeDestroy銷毀前調(diào)用適合移除事件監(jiān)聽器、解除 reactive subscriptiondestroyed銷毀后調(diào)用所有指令解綁、所有事件監(jiān)聽器移除。該筆記還特別提醒一個(gè)易錯(cuò)點(diǎn)父子組件的mounted并非按直覺順序觸發(fā)父組件的mounted不會(huì)先于子組件執(zhí)行——父組件會(huì)等待子組件 mounted 鉤子結(jié)束。4.2 React 的生命周期與 Hook 對(duì)應(yīng)React 傳統(tǒng)上以componentDidMount/componentDidUpdate/componentWillUnmount等類組件生命周期方法為主引入 Hook 后useEffect在函數(shù)組件中承擔(dān)了掛載與更新階段的副作用職責(zé)見上文 3.3 節(jié)。從面試角度可以這樣記憶Vue 把生命周期顯式劃分為四階段八鉤子React 則把掛載 更新收斂到useEffect銷毀邏輯通過useEffect返回的清理函數(shù)實(shí)現(xiàn)。五、SSR 生態(tài)對(duì)比Nuxt.js 與 Next.js原文檔雖未直接展開 SSR但兩框架的差異延伸到服務(wù)端渲染生態(tài)。倉(cāng)庫(kù)的 Web/Nuxt.js.md 說明Vue 生態(tài)使用 NuxtReact 生態(tài)使用 Next兩者的目的都是在保留 SPA 體驗(yàn)的同時(shí)解決 SEO 與首屏渲染問題。Nuxt.js 被定義為幫助 Vue.js 在服務(wù)器端渲染的開源框架可通過vue init nuxt/starter project-name快速初始化并內(nèi)置 vue-router、vuex 目錄結(jié)構(gòu)其價(jià)值在于普通 SPA 難以被搜索引擎收錄而 SSR 讓搜索機(jī)器人能直接抓取渲染后的頁(yè)面內(nèi)容從而兼顧 SEO 與 SPA 體驗(yàn)倉(cāng)庫(kù)的 Web/CSR SSR.md 進(jìn)一步補(bǔ)充了兩者取舍CSR如典型 SPA流量低、無(wú)刷新、體驗(yàn)接近原生應(yīng)用但存在 SEO 短板如 React 網(wǎng)頁(yè)源碼在瀏覽器中查看時(shí)內(nèi)容為空依賴爬蟲執(zhí)行 JS 才能索引SSR 的優(yōu)勢(shì)是 SEO 友好與首屏加載性能提升代價(jià)是項(xiàng)目復(fù)雜度上升、服務(wù)器資源占用與潛在性能惡化。這一對(duì)比直接回應(yīng)為什么 Vue/React 單頁(yè)應(yīng)用還需要 Nuxt/Next 這類框架的面試追問。六、實(shí)戰(zhàn)兩框架與 Spring Boot 集成的工程差異原文檔的差異點(diǎn)在真實(shí)工程中體現(xiàn)得最明顯的是前后端如何銜接。6.1 Vue Spring Boot 集成路徑倉(cāng)庫(kù)的 Web/Vue/Vue CLI Spring Boot ???? ?? ????.md 描述了完整流程通過 Spring Initializr 生成 Spring Boot 工程可預(yù)選 Web、JDBC、Lombok、MySQL 等依賴在 Spring Boot 根目錄下用 Vue CLI 創(chuàng)建frontend子工程修改config/index.js的 build 輸出路徑使 webpack 打包結(jié)果落入src/main/resources/static執(zhí)行npm run build靜態(tài)資源index.html、css、js即被 Spring Boot 自動(dòng)配置識(shí)別若尚未配置數(shù)據(jù)源需在主類上排除DataSourceAutoConfiguration以避免啟動(dòng)失敗package com.example.mvc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; SpringBootApplication EnableAutoConfiguration(exclude{DataSourceAutoConfiguration.class}) public class MvcApplication { public static void main(String[] args) { SpringApplication.run(MvcApplication.class, args); } }啟動(dòng)后訪問localhost:8080/即可看到 Vue 渲染的頁(yè)面。6.2 React Spring Boot 集成路徑React 側(cè)的集成文檔Web/React/React Spring Boot ???? ?? ????.md則采用JSP 承載 bundle的方案在pom.xml中引入tomcat-embed-jasper與jstl依賴以支持 JSP/JSTL通過.\mvnw spring-boot:run啟動(dòng)服務(wù)若遇 8080 端口被占用可用netstat -ao |find /i listening查 PID 后taskkill /f /im [pid]釋放端口編寫控制器把頁(yè)面名放入 ModelController public class MyController { GetMapping(/{name}.html) public String page(PathVariable String name, Model model) { model.addAttribute(pageName, name); return page; } }JSP 中聲明div idroot并引用對(duì)應(yīng) bundle 腳本script src/js/react/${pageName}.bundle.js/script由 React 在#root上完成掛載ReactDOM.render使用node_modules\.bin\webpack --watch -d持續(xù)監(jiān)聽 JSX 變更并增量打包。對(duì)比可見Vue 走構(gòu)建產(chǎn)物直接進(jìn) static 目錄由 Spring Boot 托管React 走JSP 頁(yè)面顯式引入 webpack 產(chǎn)物兩者的差異正源于各自腳手架的默認(rèn)構(gòu)建輸出約定。七、總結(jié)與面試要點(diǎn)清單回到原文檔的核心結(jié)論可以提煉為以下面試回答要點(diǎn)腳手架Vue 官方 CLI 為 vue-cliReact 官方 CLI 為 create-react-app兩者本質(zhì)都是webpack 構(gòu)建 交互式初始化。樣式組織Vue 單文件組件中style內(nèi)聯(lián)定義樣式無(wú)獨(dú)立 CSS 文件React 以獨(dú)立 CSS 文件為主在 JSX 中import后通過className應(yīng)用。數(shù)據(jù)更新Vue 中this.name lee直接賦值即可框架自動(dòng)完成依賴追蹤與重渲染調(diào)度React 必須this.setState({name:lee})函數(shù)組件則調(diào)用useState返回的 setter顯式提交更新。響應(yīng)式心智模型Vue 隱藏了賦值 → 通知 → 重渲染的流程React 要求開發(fā)者顯式聲明狀態(tài)要變并遵循不可變更新原則。延伸對(duì)比生命周期上 Vue 四階段八鉤子清晰可查React 以u(píng)seEffect收斂副作用SSR 場(chǎng)景 Vue 對(duì)應(yīng) Nuxt、React 對(duì)應(yīng) Next與 Spring Boot 集成時(shí)前者產(chǎn)物進(jìn)static、后者由 JSP 引用 bundle。若需繼續(xù)深入本主題可在倉(cāng)庫(kù)中依次閱讀 Vue 生命周期筆記、React Hook 筆記、React Fragment 筆記、CSR SSR 對(duì)比 以及 Nuxt.js 說明并結(jié)合兩篇 Vue/Spring Boot、React/Spring Boot 集成實(shí)戰(zhàn)文檔形成完整閉環(huán)。贊分享教程知識(shí)庫(kù)【免費(fèi)下載鏈接】tech-interview-for-developer ?? ??? ?? ?? ?? ?? ???? 項(xiàng)目地址https://gitcode.com/GitHub_Trending/te/tech-interview-for-developer點(diǎn)擊查看免費(fèi)下載相關(guān)推薦為每個(gè)頁(yè)面添加 Favicon從檢查清單到完整實(shí)現(xiàn)的前端 SEO 指南為每個(gè)頁(yè)面添加 Favicon從檢查清單到完整實(shí)現(xiàn)的前端 SEO 指南 Favicon 是瀏覽器標(biāo)簽頁(yè)、書簽和 Google 搜索結(jié)果中展示的小型站點(diǎn)圖標(biāo)。本教程知識(shí)庫(kù)面試必問Array vs ArrayList vs LinkedList 深度對(duì)比tech-interview-for-developer 源碼解讀面試必問Array vs ArrayList vs LinkedList 深度對(duì)比tech interview for developer 源碼解讀 導(dǎo)讀教程知識(shí)庫(kù)PyPTO 上實(shí)現(xiàn) torch.masked_fill_ 的 kernel 參考骨架gt 掩碼 where 填充的 inplace 寫回方案PyPTO 上實(shí)現(xiàn) torch.masked_fill_ 的 kernel 參考骨架gt 掩碼 where 填充的 inplace 寫回方案 本文是 Py教程知識(shí)庫(kù)上一篇RIOT 的 cppcheck 靜態(tài)檢查實(shí)踐深入 dist/tools/cppcheck 包裝腳本下一篇pandoc 中 RST 解釋文本角色I(xiàn)nterpreted Text Roles的往返轉(zhuǎn)換原理與實(shí)戰(zhàn)創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考