React Native使用useEffect避免byTest重复调用并传值至渲染层
以下是abc.tsx文件中的return语句代码:
return ( <ImageBackground source={require("../assets/images/abc.png")} style={styles.bg} > <CardStack> { byTest(globalThis.test).map((item) => ( <Card key={item.id}> <CardItemForSwiper image={item.image} name={item.name} description={item.description} /> </Card> )) } </CardStack> </ImageBackground> );
上述代码中byTest(globalThis.test)负责从其他ts文件获取数据数组,方法实现如下:
export const byTest = (test: string) => { const filData = data.filter((rawData) => { return rawData.test == test }) if (filData.length > 0) { globalThis.test = test } return new Promise((resolve)=>{return resolve(filData)}) }
现存问题
直接在JSX渲染逻辑中调用byTest(globalThis.test),会在组件每次重渲染时重复触发执行,带来不必要的性能开销。
实现目标
即使abc.tsx发生多次重渲染,byTest(globalThis.test)调用也仅触发一次。
小提示:你当前实现的
byTest内部全是同步执行的过滤逻辑,外层包裹new Promise属于多余操作,可以直接返回过滤后的数组,简化代码同时减少不必要的异步开销。
方案1:useEffect配合状态存储(通用标准方案)
这是最符合React设计逻辑的实现方式,适合绝大多数需要在组件内获取数据的场景,仅在组件首次挂载(或指定依赖变化)时触发数据获取,普通重渲染不会重复执行。
- 先引入需要的hooks
import { useEffect, useState } from 'react'; - 在组件内部定义状态和数据获取逻辑
// 存储渲染用的卡片数据 const [cardList, setCardList] = useState([]); // 空依赖数组表示仅在组件首次挂载时执行一次 // 如果需要在globalThis.test变化时重新拉取数据,把依赖数组改为[globalThis.test]即可 useEffect(() => { const fetchData = async () => { const res = await byTest(globalThis.test); setCardList(res); }; fetchData(); }, []); - 修改渲染逻辑,直接使用预取的状态数据,不要在JSX执行时调用数据方法
return ( <ImageBackground source={require("../assets/images/abc.png")} style={styles.bg} > <CardStack> {cardList.map((item) => ( <Card key={item.id}> <CardItemForSwiper image={item.image} name={item.name} description={item.description} /> </Card> ))} </CardStack> </ImageBackground> );
方案2:useMemo缓存计算结果(适合纯同步计算场景)
如果你的byTest去掉多余的Promise包装、仅做纯数据过滤、没有修改全局变量这类副作用,可以用useMemo直接缓存计算结果,不需要额外维护state,代码更简洁:
import { useMemo } from 'react'; // 组件内部直接获取缓存的计算结果 const cardList = useMemo(() => { return data.filter(rawData => rawData.test === globalThis.test); }, [globalThis.test]);
该方案下只有globalThis.test的值发生变化时才会重新执行过滤逻辑,普通重渲染会直接复用缓存结果。
方案3:模块级缓存(适合全局通用静态数据场景)
如果过滤后的数据是全局通用的,和单个组件的生命周期无关,可以直接在byTest方法内部加缓存,不管组件重渲染多少次、甚至多个组件同时调用该方法,都只会执行一次过滤逻辑:
// 模块作用域下的缓存变量,全局唯一 let cachedResult = null; let cachedTestKey = null; export const byTest = (test: string) => { // 命中缓存直接返回缓存结果 if (cachedTestKey === test && cachedResult) { return Promise.resolve(cachedResult); } const filData = data.filter((rawData) => rawData.test == test) if (filData.length > 0) { globalThis.test = test // 写入缓存 cachedTestKey = test; cachedResult = filData; } return Promise.resolve(filData) }
该方案完全不依赖React hooks,不限制调用位置,适合全局固定配置类数据的获取场景。
方案4:专业数据请求库缓存(适合中大型项目复杂场景)
如果项目中有大量数据获取、缓存、同步更新需求,可以直接使用成熟的数据请求库做自动缓存去重,不需要手动写useEffect管理状态,常用的库包括SWR、React Query。这类库会自动对相同key的请求做去重,组件重渲染、跨组件调用相同请求都不会重复触发执行,还自带重试、焦点重验证、过期更新等能力。
内容的提问来源于stack exchange,提问作者Ramu

