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

React Native实现Firebase列表筛选报Too many re-renders错误

问题根因

你碰到的Too many re-renders报错是多处写法错误共同触发的无限渲染循环:

  • onSnapshot数据监听器直接写在组件函数体中,没有用useEffect包裹:组件每次重渲染都会重新注册一次监听,监听回调里执行状态更新又会触发新一轮渲染,直接进入死循环。
  • 按钮onPress绑定逻辑错误:你写的onPress={updateSearch(1)}会在组件渲染阶段直接执行updateSearch函数,而非等用户点击后触发,函数内调用setArr更新状态会再次触发渲染,渲染又执行updateSearch,持续触发循环。
  • React的状态更新函数useState返回的set方法不支持第二个参数传回调的写法,同时你直接修改state变量的属性(比如arr.data = xxx)属于可变更新,本身就违反React状态更新规则,会额外诱发渲染异常。
  • 附带的冗余问题:从react导入了不存在的setState方法,useNavigation声明后没有初始化调用,全量数据、临时筛选数组的状态逻辑完全混乱,没有实现你最初设计的「主数组存全量、临时数组做筛选」的逻辑。

修复方案

完全按照你最初的设计逻辑实现:Firebase拉取的全量数据存在主状态中,每次筛选从主数组拷贝数据做过滤,结果交给FlatList渲染,修正后的完整代码如下:

import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, ImageBackground, FlatList, Button } from 'react-native'
import Card from '../components/Card';
import colors from '../config/colors';
import {MaterialCommunityIcons} from '@expo/vector-icons'
import { useNavigation } from '@react-navigation/core';
import { collection, query, where, onSnapshot } from 'firebase/firestore';
import {db} from '../../firebase';

// 活动类型映射:跑步1、游泳2、骑行3
function EventsPage(props) {
    const navigation = useNavigation();
    // 主数组:存储Firebase拉取的全量活动数据
    const [allEvents, setAllEvents] = useState([]);
    // 渲染数组:存储筛选后的展示结果
    const [showEvents, setShowEvents] = useState([]);

    // Firebase监听放在useEffect中,仅组件挂载时注册1次,避免重复绑定
    useEffect(() => {
        const colRef = collection(db, 'events');
        const q = query(colRef, where('type', '>=', 0));
        // 注册快照监听
        const unSubscribe = onSnapshot(q, (snapshot) => {
            const eventList = [];
            snapshot.docs.forEach((doc) => {
                eventList.push({...doc.data(), id: doc.id});
            });
            setAllEvents(eventList);
            // 首次加载默认展示全部活动
            setShowEvents(eventList);
        });
        // 组件卸载时取消监听,避免内存泄漏
        return () => unSubscribe();
    }, [])

    // 筛选逻辑:仅用户点击按钮时执行
    const handleFilter = (type) => {
        // 选全部时直接返回全量数据的拷贝
        if (type === 0) {
            setShowEvents([...allEvents]);
            return;
        }
        // 从全量主数组拷贝数据做筛选,不修改原始源数据
        const filteredResult = allEvents.filter(item => item.type === type);
        setShowEvents(filteredResult);
    }

    return (
        <View style = {styles.container}>
            <ImageBackground
                source = {require('../assets/splash-page.jpg')}
                style = {{width: '100%', height: '100%'}}
                blurRadius={8}
            >   
            <View style = {styles.backIcon}>
                <MaterialCommunityIcons 
                    name='arrow-left-bold' 
                    color="black" 
                    size={35} 
                    onPress={() => navigation.replace("Connect_me")}
                />
            </View>
            
            <Text style = {styles.text}>EVENTS</Text>
            <View style = {styles.buttons}>
                {/* onPress用箭头函数包裹,避免渲染阶段直接执行回调 */}
                <Button title={'全部'} onPress={() => handleFilter(0)}/>
                <Button title={'跑步'} onPress={() => handleFilter(1)}/>
                <Button title={'游泳'} onPress={() => handleFilter(2)}/>
                <Button title={'骑行'} onPress={() => handleFilter(3)}/>
            </View>
            <FlatList
                data={showEvents}
                keyExtractor={item => item.id}
                renderItem={({ item }) => (
                    <View style = {styles.cardContainer}>
                        <Card title={item.title} subTitle = {item.subTitle}/>
                    </View>
                )}
            />
            </ImageBackground>
        </View>
    );
}

const styles = StyleSheet.create({
    text: {
        fontSize: 80,
        textAlign:'center',
        paddingBottom: 20,
        color: colors.primary,
        fontWeight: 'bold',
    },
    container: {
        backgroundColor: 'white',
    },
    cardContainer: {
        width: '95%',
        alignSelf: 'center'
    },
    backIcon: {
        paddingLeft: 10,
        paddingTop: 30,
    }, 
    buttons: {
        flexDirection: 'row',
        padding: 20,
        justifyContent: 'space-around'
    }
})

export default EventsPage;

关键修复点说明
  • 所有数据拉取、事件监听类副作用统一放到useEffect中,依赖数组传空值保证仅组件挂载时执行一次,从根源避免重复注册监听触发的渲染循环。
  • 按钮点击事件统一用箭头函数包裹回调,只有用户实际点击时才会执行筛选逻辑,不会在渲染阶段误触发状态更新。
  • 拆分状态逻辑:全量源数据和筛选后展示的数据分开存储,每次筛选都从全量数据做浅拷贝后过滤,不会直接修改原始状态,符合React单向数据流要求。
  • 清理了无用的布尔标记、错误导入、空占位组件等冗余代码,给FlatList补充了keyExtractor属性避免列表渲染警告。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:09:22