本篇是 React Native 学习系列,我们一次性完成三件事:
-
使用
useEffect实现页面打开自动请求接口,解决无限循环坑 -
利用
useEffect依赖项,实现输入框实时搜索课程 -
封装公共 Loading 加载组件,优化网络请求用户体验
前置:Expo 项目,本地后端接口
http://localhost:3000/search,支持q查询参数做搜索。
一、useEffect:页面挂载自动请求接口
之前我们写的案例,需要点击按钮才触发请求。真实 App,打开页面就要自动加载数据。
如果你写过 Vue,初始化请求会放在 onMounted;在 React / React Native 中对应的就是 useEffect 这个 Hook。 useEffect 能力很强,可以模拟 Vue 的 onMounted、onUpdated,甚至 watch,最常用场景就是组件挂载后请求接口。
1.1 基础写法(会踩坑版本)
先引入 Hook:
js
import { useState, useEffect } from 'react';
把接口请求函数放进 useEffect:
js
const [courses, setCourses] = useState([]);
const fetchData = async () => {
const res = await fetch('http://localhost:3000/search');
const { data } = await res.json();
setCourses(data.courses);
};
// ❌ 不写依赖数组,会无限循环
useEffect(() => {
fetchData();
});
渲染列表,删掉按钮:
jsx
return (
<View style={styles.container}>
{courses.map((course) => (
<Text key={course.id}>{course.name}</Text>
))}
</View>
);
运行后打开调试工具(终端按j),你会发现接口疯狂重复请求,无限循环。
问题根源
useEffect 默认规则:组件每一次重新渲染,都会执行 useEffect
-
组件初次渲染 → 执行 useEffect → 请求接口
-
setCourses修改 state → 组件重渲染 -
重渲染后再次执行 useEffect → 再次请求,循环往复
✅ 解决方案:给 useEffect 第二个参数,**空依赖数组 **[]
js
// ✅ 空数组:仅组件挂载时执行一次
useEffect(() => {
fetchData();
}, []);
核心知识点:
不写第二个参数:每次组件渲染都会执行
[]空数组:只在组件首次挂载执行一次
完整基础版 App.js
js
import { StyleSheet, Text, View } from 'react-native';
import { useState, useEffect } from 'react';
export default function App() {
const [courses, setCourses] = useState([]);
const fetchData = async () => {
const res = await fetch('http://localhost:3000/search');
const { data } = await res.json();
setCourses(data.courses);
};
useEffect(() => {
fetchData();
}, []);
return (
<View style={styles.container}>
{courses.map((course) => (
<Text key={course.id}>{course.name}</Text>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
二、useEffect 依赖项:实现输入框实时搜索
学会挂载请求,我们进阶:利用依赖项实现搜索。
2.1 接口说明
后端接口支持查询参数 q
-
http://localhost:3000/search?q=node→ node 相关课程 -
http://localhost:3000/search?q=react→ react 相关课程
2.2 TextInput 输入框组件
React Native 使用 TextInput 实现输入框。
-
onChangeText:监听输入变化,拿到输入文本 -
placeholder:输入框提示文字
js
import { TextInput, StyleSheet, Text, View } from 'react-native';
import { useState, useEffect } from 'react';
export default function App() {
const [courses, setCourses] = useState([]);
// 搜索关键词state
const [keyword, setKeyword] = useState('');
const fetchData = async () => {
// 把keyword拼接到url参数
const res = await fetch(`http://localhost:3000/search?q=${keyword}`);
const { data } = await res.json();
setCourses(data.courses);
};
// 🎯 依赖项设置为keyword
useEffect(() => {
fetchData();
}, [keyword]);
return (
<View style={styles.container}>
<Text>您搜索的关键词是:{keyword}</Text>
<TextInput
style={styles.input}
placeholder="请填写要搜索的课程!"
onChangeText={(text) => setKeyword(text)}
defaultValue={keyword}
/>
{courses.map((course) => (
<Text key={course.id}>{course.name}</Text>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
input: {
height: 40,
width: 300,
margin: 12,
padding: 10,
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 5,
},
});
placeholder,就和HTML里表单的一样,是用来显示提示信息的。onChangeText,看名字就知道了,和JS里的onchange事件一个意思。- 当输入框的数据改变了,可以用
text来获取到用户填写的内容。 - 再调用
setKeyword将用户填写的内容,设置给keyword状态。 defaultValue就是表单里的默认值。- 为了确认到底获取到了没有?可以在最上面,加个显示
keyword的代码。

2.3 依赖项原理

useEffect 第二个数组就是依赖项数组:
数组里面的变量一旦发生改变,useEffect 就自动重新执行。
这里我们写 [keyword]: 用户打字 → keyword 更新 → 触发 useEffect → 重新请求接口,刷新列表。 打开调试网络面板可以看到:每输入一个字符就发起一次请求。
知识点汇总
无第二个参数:每次渲染执行
[]:仅挂载执行一次
[xxx]:xxx 变量改变,自动执行副作用
三、封装 Loading 加载组件,优化请求体验
网络请求是异步耗时操作,数据回来之前,页面空白会很影响体验。我们加上 loading 转圈动画。

3.1 增加 loading 状态
新增 loading state,初始值为 true,页面打开默认加载中。 使用 try...finally,无论请求成功 / 失败,finally 都会执行,关闭 loading。
js
const [loading, setLoading] = useState(true);
const fetchData = async () => {
try {
const res = await fetch(`http://localhost:3000/search?q=${keyword}`);
const { data } = await res.json();
setCourses(data.courses);
} finally {
setLoading(false);
}
};
- 给里面的内容,加上了
try...fianlly。 - 当请求完成后,在
finally里面,将加载中状态设置为false。 - 因为读取的是本地接口,请求的速度会非常非常快,会导致根本看不到什么效果。
- 我们可以在请求之前后,加上个延迟 2 秒,便于观察效果。
3.2 ActivityIndicator 原生加载指示器
React Native 内置 ActivityIndicator,原生转圈加载动画。 增加判断:如果loading=true,直接返回加载组件,不再渲染搜索和列表。
3.3 抽离公共 Loading 组件
加载组件项目多个页面都会使用,直接抽成独立组件,避免重复代码。
新建文件 components/shared/Loading.js
js
import { ActivityIndicator, StyleSheet } from 'react-native';
/**
* 全局Loading加载组件
*/
export default function Loading() {
return <ActivityIndicator size="small" color="#1f99b0" style={styles.loading} />;
}
const styles = StyleSheet.create({
loading: {
backgroundColor: '#fff',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 1,
},
});
3.4 最终完整版 App.js
js
import { TextInput, StyleSheet, Text, View } from 'react-native';
import { useState, useEffect } from 'react';
import Loading from './components/shared/Loading';
export default function App() {
const [courses, setCourses] = useState([]);
const [keyword, setKeyword] = useState('');
const [loading, setLoading] = useState(true);
const fetchData = async () => {
try {
const res = await fetch(`http://localhost:3000/search?q=${keyword}`);
const { data } = await res.json();
setCourses(data.courses);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchData();
}, [keyword]);
// 加载中渲染Loading组件
if (loading) {
return <Loading />;
}
return (
<View style={styles.container}>
<Text>您搜索的关键词是:{keyword}</Text>
<TextInput
style={styles.input}
placeholder="请填写要搜索的课程!"
onChangeText={(text) => setKeyword(text)}
defaultValue={keyword}
/>
{courses.map((course) => (
<Text key={course.id}>{course.name}</Text>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
input: {
height: 40,
width: 300,
margin: 12,
padding: 10,
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 5,
},
});
⚠️ 踩坑提醒:Android 模拟器访问
localhost会请求失败,接口地址要替换成电脑本机 IP。ActivityIndicator在 iOS 和 Android 原生样式略有差异,属于正常现象。
总结
-
useEffect是 RN 函数组件处理副作用的核心,依赖数组是灵魂-
空数组
[]:挂载执行一次 -
写入变量:变量变更,自动执行请求
-
-
TextInput实现输入框,onChangeText监听输入内容,配合 useEffect 依赖项轻松实现实时搜索 -
网络请求增加 loading 状态,使用
ActivityIndicator;通用 UI 抽离为独立组件,减少重复代码,提升复用性