useEffect Hook获取动态数据后元素未渲染的原因及修复方案
问题根因
- 核心错误:
useEffect的依赖项globalThis.test是全局普通变量,不属于React响应式状态,React无法感知它的变动,除了组件首次挂载时执行一次,后续globalThis.test无论怎么改,useEffect都不会重新执行,自然不会拉取更新后的数据。 - 初始执行问题:如果组件首次挂载时
globalThis.test没有预设匹配值,byTestOne会返回空数组,后续因为effect不触发,data状态会一直停留在空数组,map遍历自然渲染不出任何Card元素。 - 代码逻辑bug:
- mock数据源的每条记录都没有
id字段,列表渲染时key={item.id}拿到的是undefined,会触发React列表key警告,甚至导致渲染异常。 byTestOne内部逻辑倒置:只有过滤到匹配数据时才会给globalThis.test赋值,首次如果全局test为空,永远走不到赋值逻辑,直接卡死在空数据状态。
- mock数据源的每条记录都没有
修复方案
- 不要用
globalThis存需要触发UI更新的可变值,把test值改为组件内部的useState响应式状态,让React可以正常追踪值变动,自动触发effect重跑。 - 修正
byTestOne的逻辑,移除方法内部修改全局变量的代码,保持方法单一职责:只负责根据传入的test值返回过滤后的数据。 - 给列表项配置合法的key,要么给mock数据补上唯一id字段,要么临时用遍历索引当key。
修复后代码
abc.tsx
import { useState, useEffect } from 'react'; import { ImageBackground, View, Button } from 'react-native'; // 其余组件、样式引入按实际项目路径补全即可 const ABC = () => { const [data, setData] = useState<any[]>([]); // 将全局test改为组件内响应式状态,可根据业务设置默认值 const [currentTest, setCurrentTest] = useState<string>("one"); useEffect(() => { async function fetchData() { const res = await byTestOne(currentTest); setData(res); } fetchData(); }, [currentTest]); // 依赖项改为响应式状态,值变动时自动重新拉取数据 return ( <ImageBackground source={require("../assets/images/abc.png")} style={styles.bg}> <View style={styles.containerHome}> <CardStack> { data.map((item, index) => ( // 数据源未配置id时可临时用索引当key,生产环境建议给每条数据加唯一id <Card key={index}> <CardItemForSwiper name={item.name} description={item.description} /> </Card> )) } </CardStack> {/* 测试按钮:点击切换test值可验证数据是否正常更新渲染 */} <Button title="切换到test2" onPress={() => setCurrentTest("two")} /> </View> </ImageBackground> ); }; export default ABC;
byTestOne方法
// 给数据源补唯一id字段,避免列表key渲染异常 const mockData = [ { id: 1, name: "test1", description: "desc", test: "one" }, { id: 2, name: "test2", description: "desc", test: "two" } ] export const byTestOne = (test: string) => { return new Promise((resolve) => { const filData = mockData.filter((rawData) => rawData.test === test); // 移除方法内部修改全局变量的逻辑,状态统一由组件/全局状态管理工具维护 resolve(filData); }) }
如果test值需要跨多个组件全局共享,不要存在globalThis上,换成React可感知的全局状态方案(比如Context、Zustand、Redux)即可,只要保证useEffect的依赖项是响应式值,就能正常触发重跑。
内容的提问来源于stack exchange,提问作者Ramu
相关产品推荐
相关产品推荐

