TypeScript React Native函数组件Promise创建多实例异常问题排查
你遇到的现象不符合预期,是代码写法错误导致的,具体问题和修复方案如下:
问题原因
- 你的
useEffect没有传入依赖数组,会导致每一次组件重渲染都会重新执行一次useEffect回调,每次回调都新增一个2秒触发的定时器,运行时间越久,后台运行的定时器数量越多,自然会出现日志爆炸的情况。 - 你把
poll("some.key")调用写在了组件函数顶层,组件每重渲染一次就会执行一次poll函数,所以"polling"日志会不断打印,而不是只出现一次。 - 没有给定时器加清理逻辑,哪怕组件卸载了定时器还会继续运行,会造成内存泄漏。
updateValue中直接使用refreshCount变量,拿到的是闭包捕获的旧值,打印的计数不会按预期累加。
修复代码
Storage.ts 优化(可选)
你定义的poll函数已经标记了async,本身就会自动返回Promise,不需要手动创建,可以简化为:
export async function poll(key: string): Promise<any> { try { console.log("polling"); return "Promised value."; } catch (e) { // TODO: 补充异常日志 throw e; } }
ExampleAsyncComponent.tsx 修复
import React, { useEffect, useState } from "react"; import { ReactElement } from "react"; import { poll } from "./Storage"; import { Text, View } from "react-native"; export default function ExampleAsyncComponent(): ReactElement { const [value, setValue] = useState<any>(null); const [refreshCount, setRefreshCount] = useState<number>(0); const updateValue = async () => { // 把poll调用移到定时器触发逻辑内,仅每次定时执行时调用 const loadedValuePromise = poll("some.key"); const v = await loadedValuePromise; // 使用函数式更新获取最新的计数,避免闭包问题 setRefreshCount(prev => { const newCount = prev + 1; console.log("then count: " + newCount); return newCount; }); setValue(v); }; useEffect(() => { // 仅组件挂载时创建一次定时器 const timer = setInterval(() => { updateValue(); }, 2000); // 返回清理函数,组件卸载或effect重新执行前销毁定时器 return () => clearInterval(timer); }, []); // 空依赖数组,保证effect仅在组件挂载时执行一次 return ( <View> <Text>当前值:{value ?? "加载中"},刷新次数:{refreshCount}</Text> </View> ); }
补充说明
你不需要手动销毁过期的Promise,JavaScript的垃圾回收机制会自动处理没有引用的Promise对象,你只需要避免重复创建定时器这类常驻内存的逻辑即可。修复后运行效果和你的预期一致:每2秒打印一次"polling"和对应累加的计数,不会再出现日志爆炸的问题。
内容的提问来源于stack exchange,提问作者Austin Brown
相关产品推荐
相关产品推荐

