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

React Native登录异步函数执行顺序问题及加载状态实现

解决React Native登录异步流程提前触发SIGN_IN的问题

核心思路

先启动全局加载状态,等待登录请求、用户信息保存、页面配置获取所有异步操作完成后,再触发SIGN_IN动作;无论成功失败,最终关闭加载状态,避免首页提前加载。


1. 新增加载状态管理

在Redux的Auth模块中添加isLoading状态,用于控制加载页面的显示:

// authReducer.js
const initialState = {
  isAuthenticated: false,
  user: null,
  isLoading: false, // 新增加载状态
  loginError: null
};

const authReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'SET_LOADING':
      return { ...state, isLoading: action.payload };
    case 'SIGN_IN':
      return { ...state, isAuthenticated: true, user: action.payload, loginError: null };
    case 'LOGIN_FAILED':
      return { ...state, loginError: action.payload };
    default:
      return state;
  }
};

export default authReducer;

2. 重构登录异步流程

调整登录Action,确保所有异步操作完成后再触发SIGN_IN:

// authActions.js
export const signIn = (credentials) => async (dispatch) => {
  // 开启加载状态
  dispatch({ type: 'SET_LOADING', payload: true });
  
  try {
    // 1. 执行登录请求
    const loginResponse = await loginRequest(credentials);
    
    // 2. 执行后续异步操作:无依赖则用Promise.all并行提升性能
    await Promise.all([
      saveUserInfo(loginResponse.data),
      getAppScreensFromAPI(loginResponse.data.token) // 若需token则传入
    ]);
    
    // 3. 所有异步操作完成后,触发登录成功
    dispatch({ type: 'SIGN_IN', payload: loginResponse.data });
  } catch (error) {
    // 登录失败处理
    dispatch({ type: 'LOGIN_FAILED', payload: error.message });
    // 可添加弹窗提示:Alert.alert('登录失败', error.message)
  } finally {
    // 无论成功失败,关闭加载状态
    dispatch({ type: 'SET_LOADING', payload: false });
  }
};

注意:如果saveUserInfo和getAppScreensFromAPI有依赖(比如后者需要前者保存的token),则改为串行执行:

await saveUserInfo(loginResponse.data);
await getAppScreensFromAPI(); // 从本地存储取token

3. 在登录组件中显示加载页面

通过Redux获取isLoading状态,渲染加载页面或登录表单:

// LoginScreen.js
import { View, Text, TextInput, Button, ActivityIndicator, StyleSheet } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { signIn } from '../redux/actions/authActions';
import { useNavigation } from '@react-navigation/native';

const LoginScreen = () => {
  const dispatch = useDispatch();
  const navigation = useNavigation();
  const { isLoading, isAuthenticated, loginError } = useSelector(state => state.auth);
  
  // 监听登录成功状态,跳转首页
  useEffect(() => {
    if (isAuthenticated) {
      navigation.replace('Home');
    }
  }, [isAuthenticated, navigation]);
  
  const handleLogin = () => {
    const credentials = { username: 'test', password: '123456' }; // 替换为实际输入值
    dispatch(signIn(credentials));
  };
  
  // 加载中显示加载页面
  if (isLoading) {
    return (
      <View style={styles.loadingContainer}>
        <ActivityIndicator size="large" color="#2196F3" />
        <Text style={styles.loadingText}>登录中...</Text>
      </View>
    );
  }
  
  return (
    <View style={styles.container}>
      {loginError && <Text style={styles.errorText}>{loginError}</Text>}
      <TextInput style={styles.input} placeholder="用户名" />
      <TextInput style={styles.input} placeholder="密码" secureTextEntry />
      <Button title="登录" onPress={handleLogin} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', padding: 20 },
  input: { borderWidth: 1, borderColor: '#ccc', padding: 10, marginBottom: 15, borderRadius: 5 },
  errorText: { color: 'red', marginBottom: 15, textAlign: 'center' },
  loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  loadingText: { marginTop: 10, fontSize: 16 }
});

export default LoginScreen;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 03:05:26