跳转至

🔵 React 移动端 0-1 落地(技术选型 · 搭建 · 兼容 · 对标大厂)

用 React 从零做一个生产级移动端项目。本篇给技术选型方案、项目搭建步骤、兼容性处理、注意事项,并对标大厂主流方案(Meta/字节/阿里/拼多多等移动端实践)。依据 React 官方文档ViteAnt Design MobileZustand、社区大厂实践沉淀。

适用:要落地 React 移动端项目的开发者。前置:移动端基础适配方案兼容性性能专项


一、技术选型方案(React 移动端主流栈)

选型 为什么
框架 React 18 + 函数组件 + Hooks 并发特性、生态最大
构建 Vite(或 Next.js 若需 SSR) 秒级启动;SSR 见 全栈 Next
语言 TypeScript 大厂标配
UI 组件库 Ant Design Mobile (antd-mobile v5) 移动端组件全、按需引入
状态 Zustand(轻)/ Redux Toolkit(大团队) 第三方库
路由 React Router 6(hash 优先 Hybrid) hash 兼容 WebView
请求 Axios + SWR/React Query(请求缓存) 第三方库
样式 CSS Modules / Tailwind + PostCSS px-to-viewport 设计稿 px 转 vw
适配 vw + clamp + 容器查询 + viewport-fit=cover 适配
包管理 pnpm 快、严格
移动增强 antd-mobile + 手势库(如 @use-gesture/react

大厂对照

  • 阿里/蚂蚁:React + Umi + antd-mobile + TypeScript + 自研构建(同构/SSR)。
  • 字节:React + Vite + TypeScript + 自研组件库 + pnpm monorepo。
  • Meta/海外:React + Next.js(SSR/SSG)+ React Query。
  • 共同点:函数组件 + Hooks、TypeScript 全量、严格 lint、CI 卡体积、组件库二开

二、项目搭建(从 0 到跑起来)

2.1 初始化

npm create vite@latest my-mobile -- --template react-ts
cd my-mobile && pnpm i

2.2 引入 antd-mobile(按需,babel 自动)

pnpm add antd-mobile
pnpm add -D babel-plugin-import   # 或 Vite 用 unplugin-auto-import
// 直接用,配置按需
import { Button, Toast } from 'antd-mobile'
export default () => <Button color="primary">按钮</Button>

2.3 适配配置(PostCSS 自动转 vw)

// postcss.config.cjs
module.exports = {
  plugins: {
    'postcss-px-to-viewport-8-plugin': {
      viewportWidth: 375,
      unitToConvert: 'px',
      propList: ['*'],
      selectorBlackList: ['.ignore', 'adm-'],  // antd-mobile 自带适配,别二次转
      minPixelValue: 1
    }
  }
}

坑 1:antd-mobile 组件被二次转 vw 尺寸错

同 Vue 的 Vant 问题。把 adm- 加黑名单(黑名单,不是白名单),或统一用 antd-mobile 自带 viewport 方案,避免叠加。

2.4 设计稿规范与单位转换(写 px,插件自动转)

核心约定:开发时直接按设计稿写 px,由 PostCSS 插件在构建期自动转成 vw,不要人工算 vw/rem。

1)设计稿规范(团队对齐)

要求
基准宽度 375px(iPhone 标准,antd-mobile 默认基准)
标注单位 设计稿用 px 标注,开发原样写 px
倍率 @2x / @3x 切图由设计导出,开发不手动除 2
字号下限 最小 20px 起标,避免小屏糊字(iOS 最小可读)
1px 边框 用 antd-mobile hairline 或伪元素 scale不要写 0.5px(部分机型不支持)
安全区 底部 TabBar / 固定栏预留 env(safe-area-inset-bottom)
间距栅格 统一 4px 基线(4/8/12/16/24…),保证节奏一致

2)单位转换插件与职责

插件 作用 何时用
postcss-px-to-viewport-8-plugin px → vw(按 viewportWidth:375 主力,业务 px 自动转
postcss-pxtorem + amfe-flexible px → rem(动态根字号) 需要兼容老安卓 WebView 时
autoprefixer 自动加厂商前缀 必备
postcss-px-to-viewportselectorBlackList 跳过 antd-mobile 组件类(adm- 防二次转换

3)开发注意事项

  • 只写 px,别手算 vw/remwidth: 100px(设计稿量多少写多少),插件转 vw;手算易错且和插件叠加翻倍。
  • antd-mobile 组件不转selectorBlackList: ['adm-'],否则其自带适配被二次转 → 尺寸翻倍(见坑 1)。
  • 不该转的border-width: 1px 想保留物理 1px 时,把对应类加黑名单;或用 hairline
  • 媒体查询 / 动画里的 pxpropList 默认 ['*'] 会转,若某属性不想转用 ['*', '!border*'] 或加 mediaQuery: false
  • 大屏 / 平板:用 max-vw 或容器查询限制最大宽度,避免无限放大(见 适配方案)。
// postcss.config.cjs —— 写 px,自动转 vw
module.exports = {
  plugins: {
    'postcss-px-to-viewport-8-plugin': {
      viewportWidth: 375,         // 设计稿基准宽
      unitToConvert: 'px',
      propList: ['*'],
      selectorBlackList: ['adm-', 'ignore-'],  // 黑名单:antd-mobile 与 .ignore- 不转
      mediaQuery: false,          // 媒体查询里的 px 不转
      minPixelValue: 1
    },
    autoprefixer: {}
  }
}

写代码的心智模型

你眼里只有 375 设计稿的 px;vw、rem、安全区、黑名单全是构建期的"翻译层",开发时不用管。

2.5 viewport meta + 安全区

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
#root { padding-bottom: env(safe-area-inset-bottom); }


三、目录结构(推荐)

src/
├─ api/           # 接口层
├─ components/    # 业务组件
├─ hooks/         # 自定义 Hooks(useXxx)
├─ router/        # 路由 + 守卫
├─ store/         # Zustand / Redux
├─ utils/         # 工具(bridge、request)
├─ views/         # 页面
├─ styles/        # 全局样式
└─ App.tsx

用 hooks 复用逻辑

usePullRefreshuseInfiniteScrolluseBridge 封装成 hooks,页面只调。


四、路由与 Hybrid(hash 模式)

import { createHashRouter } from 'react-router-dom'
const router = createHashRouter([{ path: '/', element: <Home /> }])

坑 2:history 模式在 WebView 分享后 404

同 Vue。Hybrid/分享场景用 hash 模式(见 兼容性 §八)。


五、兼容性注意事项(React 专项)

注意
1px 边框 用 antd-mobile 的 hairline 或自定义(basics §2.2
100vh 100dvh,antd-mobile 弹层已处理
长列表 react-window / react-virtuoso 虚拟滚动
卸载清理 useEffect 的 cleanup 清定时器/Observer/Worker(性能 §五
Context 误用 高频更新别放 Context,用 Zustand(见 第三方库
低版本 WebView @vitejs/plugin-legacy + browserslist
// vite.config.ts
import legacy from '@vitejs/plugin-legacy'
plugins: [react(), legacy({ targets: ['defaults', 'not IE 11'] })]

六、性能落地(React 专项)

  • 路由懒加载const Home = lazy(() => import('./views/Home')) + <Suspense>
  • memo / useMemo / useCallback:避免子组件无谓重渲染(长列表关键)
  • 虚拟滚动react-window性能 §三
  • 图片懒加载:原生 loading="lazy"react-lazy-load
  • 请求缓存:SWR/React Query 自动缓存 + 去重
  • 分包manualChunks 拆 vendor

坑 3:列表用 index 当 key

数据重排时复用错乱、状态串台。用稳定业务 id(见 性能 §三)。

坑 4:useEffect 依赖缺失导致重复请求/内存泄漏

漏依赖 → 闭包拿旧值或卸载不取消请求。配合 AbortController原生API §5.1)。


七、对标大厂:生产级 Checklist

  • TypeScript 全量 + strict
  • pnpm + monorepo(多端复用)
  • 组件库二开(主题/规范统一)
  • 路由级懒加载 + 拆包,首屏 JS < 200KB(gzip)
  • 适配 vw + 安全区 + 折叠屏容器查询
  • 错误监控(Sentry)+ 性能监控(Web Vitals / INP)
  • CI 卡体积/单测,禁止大依赖入库
  • Hybrid 桥安全(白名单 + 超时,见 debug-hybrid
  • 离线方案(PWA 或离线包,见 pwa
  • SSR 需求走 Next.js(见 全栈 Next

八、Vue3 vs React 移动端对照

维度 Vue3 React
UI 库 Vant 4 antd-mobile v5
状态 Pinia Zustand / Redux Toolkit
逻辑复用 composables hooks
响应式 编译期自动追踪 手动 memo/useMemo
长列表 vue-virtual-scroller react-window
适配坑 Vant 别二次转 vw antd-mobile 别二次转 vw
大厂 字节/美团/滴滴 阿里/字节/拼多多

两者工程化(Vite/TS/pnpm/拆包/桥安全)高度一致,差异在框架层 API。选型看团队储备。


九、面试怎么讲(React 移动端)

面试难点与亮点。 - 难点:万行列表 INP 超标 → 虚拟滚动 + memo + 稳定 key,INP 从 320ms 降到 90ms。 - 亮点:React 移动端脚手架(antd-mobile 二开 + vw 适配 + 桥安全)被多业务复用。