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

React Native多useEffect异步问题求助:AsyncStorage与Axios调用异常

React Native异步问题:AsyncStorage与Axios API调用失败及状态未正确更新

需求

  • 向两个独立API发起认证请求获取数据
  • 在界面展示数据并附加自定义文本
  • API请求需在请求头携带从AsyncStorage获取的login_token

当前问题

  • 从AsyncStorage获取的login_token未正确同步到state
  • API调用返回的数据未正确设置到state
  • 导致API请求失败,渲染时出现undefined错误

错误原因分析

  1. 异步时序混乱:多个无依赖的useEffect同时执行,API调用时login_token、conversation_id等核心状态尚未初始化完成,请求携带空值或无效参数
  2. AsyncStorage处理不规范:getlogintoken使用回调式异步操作,无法保证状态更新完成后再执行API调用,且setLoading的位置错误
  3. useEffect依赖缺失:触发API调用的useEffect未监听login_token、conversation_id等关键状态,状态更新后不会重新发起请求
  4. 状态类型错误:currentuser从AsyncStorage获取的是JSON字符串,直接存入state后,后续JSON.parse会抛出异常
  5. welcome消息触发逻辑错误:初始化时的useEffect仅执行一次,conversation_details和ExpertProfile更新后不会重新触发消息生成

修复后的完整代码

import React, { FunctionComponent, useEffect, useCallback, useState} from 'react';
import { StyleSheet, View} from 'react-native';
import { GiftedChat } from 'react-native-gifted-chat';
import { RootStackParamList } from '../../navigators/RootStack';
import { StackScreenProps } from '@react-navigation/stack';
import { Convo_details, Send_Msg, Expert_Public_Profile } from '../../api/UserApi';
import Spinner from 'react-native-loading-spinner-overlay';
import AsyncStorage from '@react-native-async-storage/async-storage';
import uuid from 'react-native-uuid';

export type Props = StackScreenProps<RootStackParamList, "Chat">;

const Chat: FunctionComponent<Props> = ({ navigation, route }) => {
    const [login_token, setlogin_token] = useState('')
    const [conversation_id, setconversation_id] = useState('')
    const [conversation_details, setconversation_details] = useState<Record<string, any>>({})
    const [currentuser, setcurrentuser] = useState<Record<string, any>>({})
    const [loading, setLoading] = useState(false);
    const [expertuid, setexpertuid] = useState('')
    const [ExpertProfile, setExpertProfile] = useState<Record<string, any>>({})
    const [messages, setMessages] = useState([]);

    // 获取login_token
    useEffect(() => {
        const fetchLoginToken = async () => {
            try {
                const res = await AsyncStorage.getItem("login_token");
                if (res) {
                    setlogin_token(res);
                } else {
                    alert("No login token found");
                }
            } catch (err) {
                console.error("Failed to get login token:", err);
                alert("Failed to load authentication token");
            }
        };
        fetchLoginToken();
    }, []);

    // 获取路由参数
    useEffect(() => {
        if (route.params?.length >= 2) {
            setconversation_id(route.params[0]);
            setexpertuid(route.params[1]);
        }
    }, [route.params]);

    // 获取当前用户
    useEffect(() => {
        const fetchCurrentUser = async () => {
            try {
                const res = await AsyncStorage.getItem("currentuser");
                if (res) {
                    setcurrentuser(JSON.parse(res));
                } else {
                    alert("Current user not found");
                }
            } catch (err) {
                console.error("Failed to get current user:", err);
                alert("Failed to load current user");
            }
        };
        fetchCurrentUser();
    }, []);

    // 发起API请求(依赖token和参数就绪)
    useEffect(() => {
        if (!login_token || !conversation_id || !expertuid) return;
        
        const fetchData = async () => {
            setLoading(true);
            try {
                // 并行请求两个API
                const [convoRes, profileRes] = await Promise.all([
                    Convo_details(conversation_id, login_token),
                    Expert_Public_Profile(expertuid, login_token)
                ]);
                
                if (convoRes.status === 200) {
                    setconversation_details(convoRes.data);
                } else {
                    alert(`Get conversation details failed: ${convoRes.data.message}`);
                }
                
                if (profileRes.status === 200) {
                    setExpertProfile(profileRes.data);
                } else {
                    alert(`Get expert profile failed: ${profileRes.data.message}`);
                }
            } catch (error: any) {
                console.error("API request failed:", error);
                alert(`Data loading failed: ${error.message}`);
            } finally {
                setLoading(false);
            }
        };
        
        fetchData();
    }, [login_token, conversation_id, expertuid]);

    // 生成欢迎消息(依赖数据就绪)
    useEffect(() => {
        if (Object.keys(conversation_details).length === 0 || Object.keys(ExpertProfile).length === 0 || Object.keys(currentuser).length === 0) return;
        
        try {
            const welcomeMessages = [
                {
                    _id: uuid.v4().toString(),
                    conversation_id: conversation_details.conversation_id,
                    created_at: new Date(),
                    from: conversation_details.recipient.user_uid,
                    type: "TEXT",
                    text: `About Me - ${ExpertProfile.bio}`,
                    user: { _id: conversation_details.recipient.user_uid }
                },
                {
                    _id: uuid.v4().toString(),
                    conversation_id: conversation_details.conversation_id,
                    created_at: new Date(),
                    from: conversation_details.recipient.user_uid,
                    type: "TEXT",
                    text: `My name is ${conversation_details.recipient.name}`,
                    user: { _id: conversation_details.recipient.user_uid }
                },
                {
                    _id: uuid.v4().toString(),
                    conversation_id: conversation_details.conversation_id,
                    created_at: new Date(),
                    from: conversation_details.recipient.user_uid,
                    type: "TEXT",
                    text: `Hi ${currentuser.full_name}`,
                    user: { _id: conversation_details.recipient.user_uid }
                }
            ];
            setMessages(prev => GiftedChat.append(prev, welcomeMessages));
        } catch (error) {
            console.error("Failed to set welcome messages:", error);
        }
    }, [conversation_details, ExpertProfile, currentuser]);

    const onSend = useCallback(async (messages = []) => {
        if (!login_token || !conversation_id) {
            alert("Missing authentication token or conversation ID");
            return;
        }
        
        setMessages(prev => GiftedChat.append(prev, messages));
        const data = {
            conversation_id,
            message_type: "TEXT",
            body: messages[0].text
        };

        try {
            const res = await Send_Msg(data, login_token);
            if (res.status === 200) {
                console.log("Message sent successfully:", res.data);
            } else {
                alert(`Send message failed: ${res.data.message}`);
            }
        } catch (error: any) {
            console.error("Send message error:", error);
            alert(`Send message failed: ${error.message}`);
        }
    }, [login_token, conversation_id]);

    return (
        <View style={styles.maincontainer}>
            <Spinner
                visible={loading}
                textContent={'Loading...'}
                textStyle={{ color: '#FFF' }}
            />
            <GiftedChat
                messages={messages}
                onSend={onSend}
                user={{ _id: currentuser.user_uid || '' }}
                isTyping={false}
                scrollToBottom={true}
                showAvatarForEveryMessage={true}
                renderAvatar={() => null}
            />
        </View>
    );
};

export default Chat;

const styles = StyleSheet.create({
    maincontainer: {
        flex: 1,
    },
});

核心修复说明

  • 异步时序控制:所有AsyncStorage操作改用async/await,确保状态更新完成后再执行后续逻辑;API请求使用Promise.all并行发起,提升加载效率
  • 依赖项修正:API请求和欢迎消息的useEffect添加必要依赖,仅当token、参数、数据就绪时才执行
  • 状态类型处理:currentuser获取后直接解析JSON存入state,避免后续解析异常
  • 错误处理优化:统一try/catch捕获异步操作异常,提供更清晰的错误提示
  • loading状态管理:使用finally块确保请求完成后关闭loading,避免状态残留
  • 移除硬编码:替换硬编码的conversation_id为state中的动态值,保证数据一致性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 18:45:20