关于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,求助!!


  • administrators

    @KenChoi renderScene没绑this



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


  • administrators



  • @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;就报错了


  • administrators

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

    const { conversationList } = this.props;
    

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



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


登录后回复