关于react native配合redux的问题,求救!!!



  • 先贴我的代码

    下面是index.ios.js

    import React from 'react-native';
    import App from './src/ios/App';
    import { Provider } from 'react-redux';
    import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import reducer from './src/cross/reducers';
    
    const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
    const store = createStoreWithMiddleware(reducer);
    
    class iOSApp extends React.Component {
        render() {
            return(
                <Provider store={store}>
                    <App />
                </Provider>
            );
        }
    }
    
    React.AppRegistry.registerComponent('App', () => iOSApp);
    

    下面是App.js

    import React, {
        Component,
        StyleSheet,
        Navigator,
    } from 'react-native';
    
    import TabBarPage from './TabBarPage';
    import { connect } from 'react-redux';
    
    class App extends Component {
    
        render() {
            return(
                <Navigator style={styles.container}
                       initialRoute={{component: TabBarPage}}
                       configureScene={() => Navigator.SceneConfigs.FloatFromRight}
                       renderScene={(route, navigator) => <route.component navigator={navigator}
                                                                           state={this.props.state}
                                                                           dispatch={this.props.dispatch}
                                                                           {...route.passProps}  />} />
    
            );
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            backgroundColor: '#f0f4f7',
        }
    });
    
    export default connect(state => ({state: state}))(App);
    

    下面是reducers.js

    import { combineReducers } from 'redux'
    
    let reducers = {};
    
    reducers.isLogin = (state=false, action) => {
        console.log(action);
        switch (action.type) {
        case 'login':
            return true;
        case 'logout':
            return false;
        default:
            return state;
        }
    }
    
    export default combineReducers(reducers);
    

    最后在一个组件里写了下面的代码,但是不起作用

    this.props.dispatch(() => {
                return {
                    type: 'login',
                };
    });
    

    求大神指点,万份感谢!



  • dispatch调用后,reducer没有被调用



  • @tdzl2003 大神帮我看下吧?跪谢



  • 自己研究出来了,总结如下
    1,需要自动更新的容器组件就用connect注入一下状态
    2,不方便通过属性传递action的容器组件就用connect注入一下action,或者直接
    export default connect()(你的组件类名);
    不传参数默认注入dispatch到组件的props中
    在组件中通过this.props.dispatch({
    type: 'xxxxx',
    });
    来发射动作
    3,通用子组件不要用connect,通过属性来传递数据



  • @ioscoder dispatch的参数不是一个返回action的函数,而应是action本身,你写多了一个函数



  • @tdzl2003

    谢谢指出



  • @ioscoder 前面的几乎一样

    	renderScene(route, navigator) {
    		_navigator = navigator;
    		let Component = route.component;
        	return <Component 
        				{...route.params}
        				state = { this.props.state }
        				dispatch = { this.props.dispatch }
        				navigator = { navigator }
        			/>
    	}
    

    为什么我 state = { this.props.state }报错。。提示为undefined,求助!!



  • @KenChoi renderScene没绑this



  • @sunnylqm 没绑this是啥意思。。能否详细说一下:joy:





  • @sunnylqm 如果我没理解错的话,应该是在constructor里加上this.renderScene = this.renderScene.bind(this);
    这样加上以后确实没有报错,但是在Component中通过const { conversationList } = this.props.state;来拿conversationList(如果我没理解错的话这是一个Reducer对象)结果报错:undefined is not an object(evaluating 'this.props.state.conversationList')。 附上我的相关代码:

    BaseApp.js

    var _navigator;
    class BaseApp extends Component {
    
    	constructor(props) {
    		super(props);
    		this.initialRoute = {
    			name: 'mainActivity',
    			component: MainActivity,
    		}
    
    		this.renderScene = this.renderScene.bind(this);
    	}
    
    
    	componentWillMount() {
    		JMessageHelper.isLogin((map) => {
          		switch (map.result) {
            		case 're-login':
              			_navigator.replace({
                			name: 'reloginActivity',
                			component: ReloginActivity,
                			params: {
                  				username: map.username
                			}
              			});
              			console.log('user has not logged in but cached userInfo');
              			break;
            		case 'login':
              			_navigator.replace({
                			name: 'loginActivity',
                			component: LoginActivity,
                			params: {
                  				showBackBtn: false
                			}
              			});
              			console.log('user has not logged in');
              			break;
            		case 'fillInfo':
              			_navigator.replace({
                			name: 'fillInfoActivity',
                			component: FillInfoActivity,
              			});
              			break;
            		default:
              			console.log('user has logged in');
              			break;
          		}
          	});
    
      	}
    
    	configureScene() {
    		return Navigator.SceneConfigs.VerticalDownSwipeJump;
    	}
    
    	renderScene(route, navigator) {
    		_navigator = navigator;
    		let Component = route.component;
    		const { state, dispatch } = this.props;
    		const action = bindActionCreators(actions, dispatch);
        	return <Component 
        				{...route.params}
        				state = { state }
        				actions = { action }
        				navigator = { navigator }
        			/>
    	}
    
    	render() {
    		return (
    			<Navigator
    				initialRoute = { this.initialRoute }
    				configureScene = { this.configureScene }
    				renderScene = { this.renderScene }
    			/>
    			
    		);
    	}
    }
    
    function mapSateToProps(state) {
    	return {
    		state: state
    	}
    }
    
    
    export default connect(mapSateToProps) (BaseApp)
    

    actions/conversationList.js

    'use strict';
    
    import React from 'react-native';
    import * as types from './ActionTypes';
    var {
    	NativeModules,
    } = React;
    var JMessageHelper = NativeModules.JMessageHelper;
    
    
    
    export function loadConversations() {
    	return dispatch => {
    		type: types.INITIAL_CONVERSATION_LIST,
    		JMessageHelper.getConvList((result) => {
    			dispatch({
    				type: types.LOAD_CONVERSATIONS,
    				convList: JSON.parse(result),
    			});
    		});
    	}
    }
    

    reducers/conversationList.js

    import React from 'react-native';
    import * as types from '../actions/ActionTypes';
    import { combineReducers } from 'redux';
    var {
    	ListView,
    	NativeModules,
    } = React;
    var JMessageHelper = NativeModules.JMessageHelper;
    
    export default function conversationList(state, action) {
    	state = state || {
    		type: types.INITIAL_CONVERSATION_LIST,
    		convList: [],
    		dataSource: [],
    		fetching: true,
    	}
    
    	switch(action.type) {
    		case types.LOAD_CONVERSATIONS:
    			var dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
    			var convList = action.convList;
    			dataSource = dataSource.cloneWithRows(convList);
    			return {
    				...state,
    				...action,
    				convList,
    				dataSource,
    				fetching: false
    			}
    		case types.ADD_CONVERSATION:
    			var convList = [...state.convList];
    			convList.unshift(action.conversation);
    			dataSource = state.dataSource.cloneWithRows(convList);
    			return {
    				...state,
    				...action,
    				convList,
    				dataSource
    			}
    		case types.DELETE_CONVERSATION:
    			var selected = action.selected;
    			var convList = [...state.convList];
    			var index = convList.indexOf(selected);
    			convList = convList.splice(index, 1);
    			dataSource = state.dataSource.cloneWithRows(convList);
    			return {
    				...state,
    				...action,
    				convList,
    				dataSource
    			}
    		default:
    			return {
    				...state
    			}
    	}
    }
    

    containers/conv_fragment.js

    render() {
            const { conversationList } = this.props.state;
            var content = conversationList.dataSource.getRowCount() === 0 ?
                <View style = { styles.container }>
    			{ conversationList.fetching && <View style = { {alignItems: 'center', justifyContent: 'center'} }>
    					<Text style = { {fontSize: 24, }}>
    						正在加载...
    					</Text>
    				</View> } 
    			</View> :
                <ListView style = { styles.listView }
    				ref = 'listView'
    				dataSource = { conversationList.dataSource }
    				renderHeader = { this.renderHeader }
    				renderRow = { this.renderRow }
    				keyboardDismissMode="on-drag"
       				keyboardShouldPersistTaps={ true }
       				showsVerticalScrollIndicator={ false }/>;
    

    conv_fragment是通过BaseApp的Navigator启动的,在执行到const { conversationList } = this.props.state;就报错了



  • 我没有细看,但一般来说应该是

    const { conversationList } = this.props;
    

    这些问题你完全应该自己用断点调试去搞清楚数据结构。



  • @sunnylqm 是const { conversationList } = this.props.state;我忽略了一个地方,我的这个conv_fragment是在MainActivity上的Component,我没有在MainActivity中把props传过去。。另外,在Chrome上调试总是显示连接失败,我找了一些方法也没解决。。