You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native应用添加useEffects后卡顿无响应,如何解决?

解决React Native应用卡顿与无限重渲染问题

1. 修复数据库实例重复创建导致的无限查询

问题:const db = SQLite.openDatabase('db1.db')写在组件内部,每次组件渲染都会生成新的数据库实例,导致第一个useEffect的依赖[db]每次变化,触发无限次数据库查询,直接拖慢应用响应速度。

解决:将数据库实例移到组件外部,确保全局只创建一次;或者用useMemo缓存实例,避免重复生成。

修改后代码:

// 移到组件外部,全局仅初始化一次
const db = SQLite.openDatabase('db1.db');

const App = () => {
  // ... 其他代码
}

同时调整第一个useEffect的依赖,仅在组件挂载或日期变化时查询数据:

useEffect(() => {
  db.transaction(tx => {
    tx.executeSql(`SELECT * FROM Meals${date}`, null, 
      (txObj, { rows: { _array } }) => {
        setSqlData(_array);
      }) 
  })
}, [date]); // 仅依赖日期,日期变化时重新查询

2. 用SQL聚合函数直接计算Macros,减少客户端数据处理

问题:先拉取全量数据再通过forEach计算总和,当数据量大时会占用大量CPU和内存,同时每次sqlData更新都会触发重计算,增加渲染压力。

解决:直接在SQL查询中用SUM聚合函数计算宏量总和,一次查询得到结果,无需客户端处理全量数据。

修改查询逻辑(如果同时需要原始数据和总和,可以拆分为两次查询):

useEffect(() => {
  db.transaction(tx => {
    // 直接查询宏量总和
    tx.executeSql(
      `SELECT 
        SUM(protein) as protein,
        SUM(calories) as calories,
        SUM(fats) as fats,
        SUM(sugar) as sugar
      FROM Meals${date}`, 
      null, 
      (txObj, { rows: { _array } }) => {
        // 处理空表情况,避免null值
        const result = _array[0] || { protein:0, calories:0, fats:0, sugar:0 };
        setMacros({
          protein: result.protein || 0,
          calories: result.calories || 0,
          fats: result.fats || 0,
          sugar: result.sugar || 0,
        });
      }) 
  })
}, [date]);

此修改可直接移除第二个计算macros的useEffect,减少一次状态更新和重渲染触发。

3. 优化组件渲染,避免不必要的重渲染

问题:

  • getWidget函数每次渲染都会重新定义,导致renderItem内的组件频繁重渲染;
  • macros是对象类型,每次更新都会生成新引用,触发所有Rings4组件重渲染;
  • renderItem函数未缓存,拖拽或数据变化时会大量重建组件。

解决:

  • 用useCallback缓存getWidget和renderItem函数;
  • 用React.memo包裹Rings4、RecentMeals组件,避免props未变化时的重渲染。

修改代码:

import { useEffect, useState, useCallback, useMemo } from "react";

// 缓存getWidget函数
const getWidget = useCallback((type) => {
  switch(type){
    case 0: return <Rings4 macros={macros} />;
    case 1: return <RecentMeals />;
    default: return <></>;
  }
}, [macros]);

// 缓存renderItem函数
const renderItem = useCallback(({item, drag, isActive}) => {
  return (
    <ScaleDecorator activeScale={1.05}>
      <Pressable onLongPress={drag} disabled={isActive}>
        {getWidget(item.type)}
      </Pressable>
    </ScaleDecorator>
  )
}, [getWidget]);

在组件文件中添加React.memo:

// Rings4组件
import React from 'react';

const Rings4 = React.memo(({ macros }) => {
  // 原有组件逻辑
});

export default Rings4;

// RecentMeals组件同理
const RecentMeals = React.memo(() => {
  // 原有组件逻辑
});

export default RecentMeals;

4. 缓存日期字符串,避免重复计算

问题:日期字符串每次渲染都会重新生成,虽影响不大,但可通过useMemo缓存减少不必要的计算。

解决:

const date = useMemo(() => {
  const today = new Date();
  return `${today.getDate()}_${today.getMonth() + 1}_${today.getFullYear()}`;
}, []);

5. 额外优化建议

  • 如果RecentMeals需要展示大量数据,改用虚拟列表(如react-native-virtualized-list),减少同时渲染的组件数量;
  • 若数据库数据量极大,考虑分批查询,避免一次性加载过多数据;
  • 检查DraggableFlatList的动画配置,关闭不必要的动画效果以降低性能开销。

内容的提问来源于stack exchange,提问作者Thomas Rooskens

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:43:16