1. 课程导入与工程环境搭建
React Native 应用一旦离开纯本地演示阶段,就必然要面对网络请求、接口鉴权、数据缓存、离线容错、上传下载、实时通信等问题。本课程围绕“网络与数据工程”展开,目标不是记住某个 API 的调用形式,而是建立一套可复用的工程方法:知道数据从哪里来、经过哪些层、在什么条件下失败、失败后如何恢复,以及如何用可观测的手段验证结果。本章作为学习地图与起点,先厘清核心概念,再完成环境搭建,最后跑通第一个真实网络请求。
一、学习地图:从请求到数据闭环
React Native 的网络与数据工程可以拆成五个相互衔接的层次。第一层是传输层,由 fetch、XMLHttpRequest 以及底层原生网络栈承担,负责把 HTTP/HTTPS 请求发出去并接收响应。第二层是协议与接口层,关注 REST、GraphQL、WebSocket 等接口形态,以及状态码、请求头、超时、重试等约定。第三层是数据管理层,处理响应解析、类型校验、缓存、分页、乐观更新与本地持久化。第四层是状态与视图层,把远程数据映射为组件可消费的状态,处理加载中、空数据、错误、成功四种典型界面。第五层是可观测与工程化层,包括日志、错误上报、性能指标、Mock 与测试。
这五层不是必须逐层实现的瀑布,而是排查问题时的定位坐标。例如请求一直 pending,优先怀疑传输层与超时配置;数据偶发为 undefined,优先怀疑协议层字段约定或数据管理层校验缺失;界面闪烁,则多半是状态层没有区分“首次加载”和“刷新”。
二、核心概念:先统一几个容易混淆的词
请求与响应:一次网络交互由请求方法、URL、请求头、请求体组成,服务端返回状态码、响应头与响应体。React Native 中 fetch 返回的 Promise 只有在网络层失败时才 reject;HTTP 404、500 这类“服务器有响应但状态码非 2xx”的情况,Promise 仍然 resolve,必须手动检查 response.ok 或 response.status。这是初学者最常见的坑。
序列化与反序列化:请求体通常需要 JSON.stringify,响应体需要 response.json()。注意 response.json() 本身也返回 Promise,且只能读取一次响应体。
超时与取消:fetch 默认没有超时,需要借助 AbortController 主动中断。组件卸载后仍 setState 会触发警告,因此取消请求是工程必备。
环境变量与接口地址:开发、测试、生产环境的 baseURL 不同。React Native 没有浏览器那样的 process.env 注入,常用做法是用 react-native-config 或自建 env.ts 按 __DEV__ 分支导出配置。
三、开发环境搭建
推荐使用 Expo 起步,它屏蔽了大部分原生配置,适合把精力放在网络与数据逻辑上。若后续需要接入自定义原生模块,再执行 npx expo prebuild 转为原生工程。
# 1. 创建项目
npx create-expo-app rn-net-lab --template blank-typescript
cd rn-net-lab
# 2. 安装网络与调试相关依赖
npx expo install @react-native-async-storage/async-storage
npm i axios zustand
# 3. 启动开发服务器
npx expo start
启动后可用 Expo Go 扫码在真机运行,或按 a / i 启动模拟器。真机调试时注意:手机与电脑需在同一局域网;若接口部署在本机,Android 模拟器访问宿主机要用 10.0.2.2,iOS 模拟器可直接用 localhost,真机则需使用电脑的局域网 IP。
src/config/env.ts,集中管理 baseURL 与超时时间,避免接口地址散落在各个组件中。四、第一个网络请求示例
下面用一个公开测试接口 https://jsonplaceholder.typicode.com/posts/1 演示完整流程:发起请求、检查状态码、解析 JSON、渲染结果,并处理加载与错误状态。示例中的返回数据为公开测试接口的典型结构,仅用于教学演示。
import React, { useEffect, useState } from 'react';
import { View, Text, ActivityIndicator, Button } from 'react-native';
type Post = { userId: number; id: number; title: string; body: string };
export default function FirstRequest() {
const [data, setData] = useState<Post | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const load = async () => {
setLoading(true);
setError(null);
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 8000);
try {
const res = await fetch(
'https://jsonplaceholder.typicode.com/posts/1',
{ signal: controller.signal }
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json: Post = await res.json();
setData(json);
} catch (e: any) {
setError(e.name === 'AbortError' ? '请求超时' : e.message);
} finally {
clearTimeout(timer);
setLoading(false);
}
};
useEffect(() => { load(); }, []);
if (loading) return <ActivityIndicator size="large" />;
if (error) return <View><Text>出错:{error}</Text><Button title="重试" onPress={load} /></View>;
return (
<View>
<Text>{data?.title}</Text>
<Text>{data?.body}</Text>
</View>
);
}
运行后应看到标题与正文文本。若长时间转圈,检查网络与接口地址;若显示“出错:HTTP 404”,说明路径写错;若显示“请求超时”,说明 8 秒内未收到响应。这个最小闭环已经包含了后续所有章节都会反复用到的骨架:状态三件套(data / loading / error)+ 超时控制 + 状态码检查 + 重试入口。
五、本章实践检查清单
| 检查项 | 预期结果 | 不通过时的排查方向 |
|---|---|---|
| 项目可启动 | Expo 开发服务器正常,真机或模拟器可加载 | Node 版本、依赖安装、局域网连通性 |
| 接口可访问 | 返回 200 且 JSON 含 id/title/body | URL 拼写、baseURL、模拟器宿主地址 |
| 加载态可见 | 请求期间显示 ActivityIndicator | loading 状态是否在 finally 中复位 |
| 错误态可重试 | 断网或改错 URL 后显示错误并可点击重试 | 是否检查 res.ok、是否捕获 AbortError |
| 超时生效 | 8 秒无响应时提示“请求超时” | AbortController 是否绑定到 signal |