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,且navigationprops能正常传递给组件 appReducer的初始状态是loading: true,所以组件挂载后默认会显示加载状态,除非你主动调用appLoaded()
内容的提问来源于stack exchange,提问作者user259752
相关产品推荐
相关产品推荐

