Vue 與 React 常見對照
將專案從vue轉成react時順便紀錄:
文章目錄
狀態與資料
| Vue 3 | React | 差異重點 |
| ref() / reactive() | useState | React 不能直接改值,必須呼叫 setXxx,物件要複製出新的 |
| computed() | useMemo | Vue 自動追蹤依賴;React 要自己寫依賴陣列 |
| watch(x, fn) | useEffect(fn, [x]) | 依賴變了就執行 |
| onMounted | useEffect(fn, []) | 依賴陣列為空 = 只在掛載時執行一次 |
| onUnmounted | useEffect 回傳的清理函式 | return () => clearInterval(timer)(Dashboard.tsx) |
| ref="el" 取 DOM | useRef | 也用來存「不影響畫面」的值 |
元件之間傳資料
| Vue 3 | React | 本專案例子 |
| props | 函式參數 { width } | LocaleSelect({ width }) |
| emit('事件’) | 把函式當 props 傳下去,子元件呼叫它 | Select 的 onChange |
| provide / inject | Context(createContext + useContext) | SystemDataContext、ScanContext、PageMetaContext |
| <slot> | children | ScanProvider({ children }) |
| v-model | value + onChange 兩個一起寫 | <Input value={wordKey} onChange={…} /> |
模板語法
| Vue | React (JSX) |
| v-if="x" | {x && <div/>} 或 {x ? <A/> : <B/>} |
| v-for="i in list" :key="i.id" | {list.map(i => <li key={i.id}/>)} |
| {{ text }} | {text} |
| :class="{ active: x }" | className={x ? 'active’ : "} |
| class="…" | className="…"(class 是 JS 保留字) |
| @click="fn" | onClick={fn} |
| :disabled="x" | disabled={x} |
| v-show | style={{ display: x ? 'block’ : 'none’ }} |
| $t('key’) | const { t } = useTranslation() 再 t('key’) |
路由
| Vue Router | React Router |
| <router-view> | <Outlet />(MainLayout.tsx) |
| router.push('/x’) | navigate('/x’),const navigate = useNavigate() |
| router.back() | navigate(-1) |
| this.$route.query.reqno | const [params] = useSearchParams() 再 params.get('reqno’) |
| router.beforeEach | 路由守衛元件(RequireAuth) |
三個最容易踩雷的差異
1. 更新是「重新執行整個函式」,不是「追蹤變動」
Vue 的 setup() 只跑一次;React 的元件函式每次更新都會從頭跑。元件裡的普通變數在每次渲染都會重新建立,要保留的值必須放 useState 或 useRef。
2. useEffect 的依賴陣列是你的責任
useEffect(() => { load() }, [range, dept]) // range 或 dept 變了才重新執行
漏寫會拿到舊值,多寫會執行太頻繁。專案裡有幾處加了 // eslint-disable-next-line react-hooks/exhaustive-deps,是刻意不列入某些依賴,旁邊有寫原因。
3. 開發模式 useEffect 會跑兩次
這是 StrictMode 的行為,正式版不會。所以 effect 裡要能「清理乾淨」,例如計時器要 clearInterval。
對照速記
- Vue 是「響應式」:你改資料,框架知道誰依賴它。
- React 是「重新計算」:你通知它資料變了,它重新執行元件,再比對差異更新畫面。