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

Redux通过dispatch reducer无法更新全局状态问题排查求助

问题描述

调用dispatch reducer后全局状态未更新,预期HomeScreen组件会一直显示加载页面,但实际并未实现。


项目相关代码文件

index.js

import React from 'react'; 
import { AppRegistry } from 'react-native' 
import App from './App'; 
import { YellowBox } from 'react-native'; 
YellowBox.ignoreWarnings(['Warning: isMounted(...) is deprecated', 'Module RCTImageLoader']); 
AppRegistry.registerComponent('mhagora', () => App);

App.js

import React, { Component } from 'react'; 
import { Provider } from "react-redux"; 
import store from './app/store'; 
import { StyleProvider, getTheme } from "native-base"; 
import Setup from "./app/setup"; 
import variables from "./app/theme/variables/commonColor"; 

export default class App extends Component { 
  render() { 
    return ( 
      <Provider store={store}> 
        <StyleProvider style={getTheme(variables)}> 
          <Setup /> 
        </StyleProvider> 
      </Provider> 
    ); 
  } 
}

./app/setup.js

import React, { Component } from "react"; 
import axios from "axios/index"; 
import Config from "./config"; 
import { Root } from "native-base"; 
import AppNavigator from "./routes"; 

axios.defaults.baseURL = Config.API_BASE_URL; 
axios.defaults.headers.common['Content-Type'] = Config.API_ACCEPT; 
axios.defaults.headers.common['Accept'] = Config.API_ACCEPT; 
axios.defaults.headers.common['secret'] = Config.API_SECRET; 

export default class Setup extends Component { 
  render() { 
    return ( 
      <Root> 
        <AppNavigator /> 
      </Root> 
    ); 
  } 
}

./app/store/index.js

import { createStore, applyMiddleware, compose } from 'redux'; 
import thunk from 'redux-thunk'; 
import { createLogger } from 'redux-logger'; 
import reducers from '../reducers'; 

const logger = createLogger(); 
export default createStore(reducers, compose(applyMiddleware(thunk, logger)));

./app/actions/index.js

import { APP_LOADING, APP_LOADED } from '../actionTypes'; 

export function appLoading() { 
  return (dispatch) => { 
    dispatch({type: APP_LOADING}); 
  } 
} 

export function appLoaded() { 
  return (dispatch) => { 
    dispatch({type: APP_LOADED}); 
  } 
}

./app/actions/user.js

import { USER_LOADING, USER_LOADED, USER_FAILED, APP_LOADING, APP_LOADED } from "../actionTypes"; 
import axios from 'axios'; 
import Config from '../config'; 

export function userLogin(username, password) { 
  return (dispatch) => { 
    dispatch({type: USER_LOADING}); 
    axios 
      .post("oauth/token", { 
        username: username, 
        password: password, 
        client_id: Config.API_CLIENT_ID, 
        client_secret: Config.API_CLIENT_SECRET, 
        grant_type: 'password', 
      }, { headers: {} }) 
      .then(response => { 
        dispatch({ type: USER_LOADED, data: response.data }); 
      }) 
      .catch(err => { 
        dispatch({ type: USER_FAILED, error: err.response.data.message }); 
        alert(err.response.data.message); 
      }); 
  }; 
}

./app/reducers/index.js

import appReducer from './appReducer'; 
import userReducer from './userReducer'; 
import { combineReducers } from "redux"; 

const rootReducer = combineReducers({ 
  appReducer, 
  userReducer 
}); 

export default rootReducer;

./app/reducers/userReducer.js

import { USER_LOADING, USER_LOADED, USER_FAILED } from '../actionTypes'; 

const initialState = { 
  username: "", 
  password: "", 
  user: {} 
}; 

export default userReducer = (state = initialState, action) => { 
  switch (action.type) { 
    case USER_LOADING: 
      return Object.assign({}, state, { 
        loading: true, 
        user: {}, 
      }); 
    case USER_LOADED: 
      return Object.assign({}, state, { 
        loading: false, 
        user: action.data 
      }); 
    case USER_FAILED: 
      return Object.assign({}, state, { 
        loading: false, 
      }); 
    default: return state 
  } 
}

./app/reducers/appReducer.js

import { APP_LOADING, APP_LOADED } from "../actionTypes"; 

const initialState = { 
  loading: true, 
}; 

export default appReducer = (state = initialState, action) => { 
  switch (action.type) { 
    case APP_LOADING: 
      return Object.assign({}, state, { loading: true }); 
    case APP_LOADED: 
      return Object.assign({}, state, { loading: false }); 
    default: return state; 
  } 
};

./app/screens/home.js

'use strict'; 
import React, { Component } from 'react'; 
import { bindActionCreators } from 'redux'; 
import { connect } from 'react-redux'; 
import { SkypeIndicator } from 'react-native-indicators'; 
import * as Actions from '../actions/index'; 
import { Container, Header, Title, Content, Footer, FooterTab, Button, Left, Right, Body, Icon, Text, View } from 'native-base'; 

class HomeScreen extends Component { 
  componentDidMount() { 
    /** 此处应用本该一直显示加载页面,但实际并未实现 **/ 
    // setTimeout( _ => { 
    //   this.props.appLoaded(); 
    // }, 2000); 
  } 

  render() { 
    if (this.props.loading) { 
      return ( 
        <SkypeIndicator /> 
      ); 
    } else { 
      return ( 
        <Container> 
          <Header> 
          </Header> 
          <Body> 
            <Button onPress={() => this.props.navigat

问题分析与解决方案

看起来你的核心问题是HomeScreen组件没有正确连接到Redux Store,导致无法获取到全局的loading状态,自然无法触发加载页面的显示。我们来一步步修复:

1. 核心问题:HomeScreen未完成Redux连接

你的home.js只导入了connect和bindActionCreators,但没有实现mapStateToProps来映射Redux中的状态到组件props,也没有用connect包裹组件导出。这直接导致this.props.loading是undefined,组件永远不会进入加载分支。

2. 修复后的HomeScreen代码

'use strict';
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { SkypeIndicator } from 'react-native-indicators';
import * as Actions from '../actions/index';
import { Container, Header, Title, Content, Footer, FooterTab, Button, Left, Right, Body, Icon, Text, View } from 'native-base';

class HomeScreen extends Component {
  componentDidMount() {
    // 若要保持加载状态,请勿调用appLoaded(),保持注释即可
    // setTimeout( _ => {
    //   this.props.appLoaded();
    // }, 2000);
  }

  render() {
    // 现在能正确获取到redux中的loading状态了
    if (this.props.loading) {
      return (
        <SkypeIndicator />
      );
    } else {
      return (
        <Container>
          <Header>
            <Left />
            <Body>
              <Title>Home</Title>
            </Body>
            <Right />
          </Header>
          <Content>
            <Text>Home Screen Content</Text>
            {/* 补全导航代码,示例为跳转到登录页 */}
            <Button onPress={() => this.props.navigation.navigate('Login')}>
              <Text>Go to Login</Text>
            </Button>
          </Content>
        </Container>
      );
    }
  }
}

// 将Redux store中appReducer的loading状态映射到组件props
const mapStateToProps = (state) => {
  return {
    loading: state.appReducer.loading
  };
};

// 将action creators映射到组件props
const mapDispatchToProps = (dispatch) => {
  return bindActionCreators(Actions, dispatch);
};

// 用connect包裹组件并导出
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);

3. 额外检查点

  • 确认AppNavigator已正确注册HomeScreen,且navigation props能正常传递给组件
  • appReducer的初始状态是loading: true,所以组件挂载后默认会显示加载状态,除非你主动调用appLoaded()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:13:48