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

React Native FlatList加载更多时崩溃问题求助

React Native FlatList加载更多后崩溃问题

问题现象

初始加载时FlatList表现正常,触发加载更多更新状态后组件崩溃,尝试多种状态更新方式无效,未在谷歌找到同类问题,本人刚接触React Native,对其特性了解有限。

问题截图

加载更多导致列表崩溃
初始加载正常

原代码

// React
import React, {useContext, useState, useEffect} from 'react';
import {View, Text, TouchableWithoutFeedback, FlatList} from "react-native";
import {MaterialCommunityIcons} from "@expo/vector-icons";
import * as Yup from "yup";
import {ray} from 'node-ray/web';

import AuthContext from "../../../auth/context";
import AppContainer from "../../../components/AppContainer";
import ChatContext from "../../../context/chats-context";
import ChatsApi from "../../../api/chats";
import Form from "../../../components/form/Form";
import FormInputDefault from "../../../components/form/FormInputDefault";
import FormIconButton from "../../../components/form/FormIconButton";
import RenderChatMessageItem from "../../../components/chat/RenderChatMessageBox";

import tw from "../../../lib/tailwind";

const validationSchema = Yup.object().shape({
    message: Yup.string().required().label("Message"),
});

function SharedMessagesShow({ navigation, route }) {
    const chatContext = useContext(ChatContext);
    const { user } = useContext(AuthContext);
    const { data } = route.params;
    const [ chat, setChat ] =  useState(JSON.parse(data));
    const [ currentPage, setCurrentPage ] = useState(1);
    const [ maxListItems, setMaxListItems ] = useState(10);
    const [ loading, setLoading ] = useState(false);

    const loadOlderMessages = async () => {

        if (loading) {
            return
        }

        setLoading(true);

        const response = await ChatsApi.getMoreMessages(chat.id, user.user.id, currentPage + 1);

        if (!response.ok) {
            return null;
        }

        if (maxListItems < response.data.total)
        {
            const newChat = {...chat};

            let newPage = currentPage + 1;
            let newMaxItems = maxListItems + response.data.messages.length;

            setCurrentPage(newPage);
            setMaxListItems(newMaxItems);

            newChat.messages = newChat.messages.concat(response.data.messages);

            ray(newChat);

            setChat(newChat);

            setLoading(false);
        }


    }

    const handleSendMessage = async ({message}, resetForm) => {
        const toUser = chat.users.find(chatUser => { return chatUser.user_id !== user.user.id })

        const response = await ChatsApi.sendMessage(chat.id, message, user.user.id, toUser.id);
        if (!response.ok) {
            return null;
        }

        const newChat = {...chat};

        newChat.messages.shift();
        newChat.messages.push(response.data);

        setChat(newChat);

        resetForm();
    }

    useEffect(() => {
    }, [chat, chat.messages, maxListItems]);


    return (
        <AppContainer bgColour={'gray-100'}>
            <View style={tw`justify-between flex flex-1`}>
                <View style={tw`bg-white p-3 flex flex-row justify-between items-center`}>
                    <View style={tw`flex`}>
                        <Text>{chat.to_user.first_name} {chat.to_user.last_name}</Text>
                        <Text>{chat.application.job_name}</Text>
                        <Text>{chat.application.status}</Text>
                    </View>
                    <View style={tw`flex mr-3`}>
                        <TouchableWithoutFeedback onPress={() => navigation.navigate('Chat Calendar')}>
                            <MaterialCommunityIcons name={'calendar-clock'} size={25} color={'#000000'}/>
                        </TouchableWithoutFeedback>
                    </View>
                </View>
                <View style={tw`flex flex-1 p-3`}>
                    <FlatList
                        inverted={true}
                        data={chat.messages}
                        onEndReachedThreshold={0.1}
                        renderItem={ message => <RenderChatMessageItem message={message} fromUser={user.user}/> }
                        keyExtractor={ message => message.id.toString()}
                        onEndReached={loadOlderMessages}
                        extraData={maxListItems}
                        initialNumToRender={maxListItems}
                    />
                </View>
                <View style={tw`flex w-full`}>
                    <Form
                        initialValues={{ message: "" }}
                        onSubmit={ (values, {resetForm}) => handleSendMessage(values, resetForm) }
                        validationSchema={validationSchema}
                    >
                        <View style={tw`flex flex-row w-full p-1`}>
                            <FormInputDefault
                                name="message"
                                placeholder="Message"
                                textContentType="none"
                                autoCapitalize="sentences"
                                autoCorrect={true}
                                multiline={true}
                                textAlignVertical={true}
                                scrollEnabled={true}
                                styles='w-5/6 bg-white flex px-8 pt-3 pb-1 rounded-3xl max-h-20'
                            />
                            <View style={tw`w-1/6 justify-center items-center`}>
                                <FormIconButton defaultText='+' />
                            </View>
                        </View>
                    </Form>
                </View>
            </View>
        </AppContainer>
    );
}

export default SharedMessagesShow;

修复后的代码

// React
import React, {useContext, useState, useEffect} from 'react';
import {View, Text, TouchableWithoutFeedback, FlatList} from "react-native";
import {MaterialCommunityIcons} from "@expo/vector-icons";
import * as Yup from "yup";
import {ray} from 'node-ray/web';

import AuthContext from "../../../auth/context";
import AppContainer from "../../../components/AppContainer";
import ChatContext from "../../../context/chats-context";
import ChatsApi from "../../../api/chats";
import Form from "../../../components/form/Form";
import FormInputDefault from "../../../components/form/FormInputDefault";
import FormIconButton from "../../../components/form/FormIconButton";
import RenderChatMessageItem from "../../../components/chat/RenderChatMessageBox";

import tw from "../../../lib/tailwind";

const validationSchema = Yup.object().shape({
    message: Yup.string().required().label("Message"),
});

function SharedMessagesShow({ navigation, route }) {
    const chatContext = useContext(ChatContext);
    const { user } = useContext(AuthContext);
    const { data } = route.params;
    const [ chat, setChat ] =  useState(JSON.parse(data));
    const [ currentPage, setCurrentPage ] = useState(1);
    const [ maxListItems, setMaxListItems ] = useState(10);
    const [ loading, setLoading ] = useState(false);

    const loadOlderMessages = async () => {
        if (loading) return;
        setLoading(true);

        const response = await ChatsApi.getMoreMessages(chat.id, user.user.id, currentPage + 1);
        if (!response.ok) {
            setLoading(false);
            return null;
        }

        if (maxListItems < response.data.total) {
            setCurrentPage(prev => prev + 1);
            setMaxListItems(prev => prev + response.data.messages.length);
            
            setChat(prevChat => {
                const newChat = {...prevChat};
                newChat.messages = [...response.data.messages, ...prevChat.messages];
                return newChat;
            });
        }
        setLoading(false);
    }

    const handleSendMessage = async ({message}, resetForm) => {
        const toUser = chat.users.find(chatUser => chatUser.user_id !== user.user.id);
        const response = await ChatsApi.sendMessage(chat.id, message, user.user.id, toUser.id);
        if (!response.ok) return null;

        setChat(prevChat => {
            const newChat = {...prevChat};
            newChat.messages = [...prevChat.messages.slice(1), response.data];
            return newChat;
        });
        resetForm();
    }

    useEffect(() => {}, [chat, currentPage, maxListItems]);

    return (
        <AppContainer bgColour={'gray-100'}>
            <View style={tw`justify-between flex flex-1`}>
                <View style={tw`bg-white p-3 flex flex-row justify-between items-center`}>
                    <View style={tw`flex`}>
                        <Text>{chat.to_user.first_name} {chat.to_user.last_name}</Text>
                        <Text>{chat.application.job_name}</Text>
                        <Text>{chat.application.status}</Text>
                    </View>
                    <View style={tw`flex mr-3`}>
                        <TouchableWithoutFeedback onPress={() => navigation.navigate('Chat Calendar')}>
                            <MaterialCommunityIcons name={'calendar-clock'} size={25} color={'#000000'}/>
                        </TouchableWithoutFeedback>
                    </View>
                </View>
                <View style={tw`flex flex-1 p-3`}>
                    <FlatList
                        inverted={true}
                        data={chat.messages}
                        onEndReachedThreshold={0.1}
                        renderItem={ ({item: message}) => <RenderChatMessageItem message={message} fromUser={user.user}/> }
                        keyExtractor={ message => message.id.toString()}
                        onEndReached={loadOlderMessages}
                        extraData={chat}
                        initialNumToRender={10}
                    />
                </View>
                <View style={tw`flex w-full`}>
                    <Form
                        initialValues={{ message: "" }}
                        onSubmit={ (values, {resetForm}) => handleSendMessage(values, resetForm) }
                        validationSchema={validationSchema}
                    >
                        <View style={tw`flex flex-row w-full p-1`}>
                            <FormInputDefault
                                name="message"
                                placeholder="Message"
                                textContentType="none"
                                autoCapitalize="sentences"
                                autoCorrect={true}
                                multiline={true}
                                textAlignVertical="top"
                                scrollEnabled={true}
                                styles='w-5/6 bg-white flex px-8 pt-3 pb-1 rounded-3xl max-h-20'
                            />
                            <View style={tw`w-1/6 justify-center items-center`}>
                                <FormIconButton defaultText='+' />
                            </View>
                        </View>
                    </Form>
                </View>
            </View>
        </AppContainer>
    );
}

export default SharedMessagesShow;

核心修复点

  1. RenderItem参数修正:FlatList的renderItem回调参数是包含item的对象,原代码直接传递整个对象导致组件拿到错误数据,修复为解构item:({item: message}) => ...。
  2. 状态更新逻辑优化:
    • 加载更多时使用函数式更新获取最新状态,避免异步操作引发的状态不一致。
    • 更新chat时通过函数式更新获取最新快照,同时深拷贝数组避免修改原state引用。
  3. FlatList配置调整:
    • extraData改为依赖chat,确保消息列表更新时FlatList能正确触发重渲染。
    • initialNumToRender设为固定初始值,该属性仅控制首次渲染数量,无需动态修改。
    • 针对inverted={true}的特性,将旧消息添加到数组开头,保证显示顺序符合聊天逻辑。
  4. 消息发送时的数组操作修正:用slice(1)创建新数组替代shift(),避免直接修改原state数组。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 21:33:22