TypeError:undefined不是函数(评估调度)

时间:2018-01-04 17:40:29

标签: javascript reactjs react-redux

我正在尝试将React Redux与React Native结合使用,我在调试程序时遇到了这个奇怪的错误:

TypeError: undefined is not a function (evaluating 'dispatch((0, _LoginActions.loginAction)(inputFormProp))')

在我运行程序后立即从组件的登录功能中触发错误,我不知道为什么会有这个错误。

这是我的组件代码:

import React, { Component } from 'react';
import { Text, View, TextInput, ActivityIndicator, TouchableHighlight } from 'react-native';
import { getLogger, issueToText } from '../core/utils';
import styles from '../core/styles';
import { Card, Button, FormLabel, FormInput } from "react-native-elements";
import { connect } from 'react-redux'
import { loginAction } from '../actions/LoginActions'

export class LoginComponent extends Component {
constructor(props) {
    super(props);
    this.login = this.login.bind(this)
}

render() {
    const { error, isLoading } = this.props;

    const inputFormProp = {
        username: '',
        password: ''
    };

    return (
        <View style={{ paddingVertical: 20 }}>
            <Card>
                <FormLabel>Email</FormLabel>
                <FormInput value={inputFormProp.username} onChangeText={(text) => inputFormProp.username = text} />
                <FormLabel>Password</FormLabel>
                <FormInput value={inputFormProp.password} onChangeText={(text) => inputFormProp.password = text} />

                <Button
                    buttonStyle={{ marginTop: 20 }}
                    backgroundColor="#03A9F4"
                    title="SIGN IN"
                    onPress={this.login(inputFormProp)}
                />
            </Card>
            <ActivityIndicator animating={this.props.isLoading} style={styles.activityIndicator} size="large" />
        </View>
    );
}


login(inputFormProp) {
    const { store } = this.props.screenProps.store;

    const { dispatch } = this.props

    dispatch(loginAction(inputFormProp))
        .then(() => {
            if (this.props.error === null && this.props.isLoading === false) {
                if (store.getState().auth.token) {
                    this.props.navigation.navigate('ProductList', { token: store.getState().auth.token });
                }
            }
        })
        .catch(error => {
        });
}


}

function mapStateToProps(state) {
const { error, isLoading } = state.auth

return {
    error,
    isLoading,
}
}

export default connect(mapStateToProps)(LoginComponent)

这是我的app.js代码:

const initialState = {
  auth: { isLoading: false, error: null },
};


const rootReducer = combineReducers({ product: productReducer, auth: authReducer 
});

const store = createStore(rootReducer, initialState, applyMiddleware(thunk, 
createLogger()));

export const MyNavigator = StackNavigator({
  Login: { screen: LoginComponent },
  ProductList: { screen: ProductList },
});



export default class App extends Component {
  render() {
    return (
      <MyNavigator screenProps={{ store: { store } }} />
    );
  }
};

根据我已经搜索过的错误,似乎原因是我的组件中的connect()函数,但我不知道它有什么问题。

这是我的目录结构:

enter image description here

这是LoginActions文件:

import { loginService } from '../services/LoginService'

export function loginAction(data) {
    return dispatch => {
        loginService(data);
    }
}

这是LoginService文件:

import { httpApiUrl } from '../core/api';
import { getLogger } from "../core/utils";
import { Alert } from 'react-native';
const log = getLogger('auth/service');


export const loginService = (user) => (dispatch) => {
dispatch({ type: 'LOGIN_STARTED' });
return fetch(`${httpApiUrl}/api/userdata/verify`, {
    method: 'POST',
    headers: {
        'Accept': '*/*',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify(user)
})
    .then((response) => {
        if (!response.ok) {
            Alert.alert('ERROR', 'User or password is incorrect');
            dispatch({ type: 'LOGIN_FAILED', data: 'User or password is incorrect' });
        }
        else return response;
    }).then((response) => response.json).then((response) => {
        dispatch({ type: 'LOGIN_SUCCEEDED', data: response.json });

    })
    .catch(error => {
        dispatch({ type: 'LOGIN_FAILED', data: error.message });
    });
};

这是this.props的输出

21:10:48: Object {
21:10:48:   "navigation": Object {
21:10:48:     "dispatch": [Function anonymous],
21:10:48:     "goBack": [Function goBack],
21:10:48:     "navigate": [Function navigate],
21:10:48:     "setParams": [Function setParams],
21:10:48:     "state": Object {
21:10:48:       "key": "Init-id-1515093047465-0",
21:10:48:       "routeName": "Login",
21:10:48:     },
21:10:48:   },
21:10:48:   "screenProps": Object {
21:10:48:     "store": Object {
21:10:48:       "store": Object {
21:10:48:         "@@observable": [Function observable],
21:10:48:         "dispatch": [Function anonymous],
21:10:48:         "getState": [Function getState],
21:10:48:         "replaceReducer": [Function replaceReducer],
21:10:48:         "subscribe": [Function subscribe],
21:10:48:       },
21:10:48:     },
21:10:48:   },
21:10:48: }

2 个答案:

答案 0 :(得分:2)

您需要在类声明

之前删除带前缀的export关键字
class LoginComponent extends Component { //<--- export was present here 
constructor(props) {
    super(props);
    this.login = this.login.bind(this)
}

render() {
    const { error, isLoading } = this.props;

    const inputFormProp = {
        username: '',
        password: ''
    };

    return (
        <View style={{ paddingVertical: 20 }}>
            <Card>
                <FormLabel>Email</FormLabel>
                <FormInput value={inputFormProp.username} onChangeText={(text) => inputFormProp.username = text} />
                <FormLabel>Password</FormLabel>
                <FormInput value={inputFormProp.password} onChangeText={(text) => inputFormProp.password = text} />

                <Button
                    buttonStyle={{ marginTop: 20 }}
                    backgroundColor="#03A9F4"
                    title="SIGN IN"
                    onPress={this.login(inputFormProp)}
                />
            </Card>
            <ActivityIndicator animating={this.props.isLoading} style={styles.activityIndicator} size="large" />
        </View>
    );
}


login(inputFormProp) {
    const { store } = this.props.screenProps.store;

    const { dispatch } = this.props

    dispatch(loginAction(inputFormProp))
        .then(() => {
            if (this.props.error === null && this.props.isLoading === false) {
                if (store.getState().auth.token) {
                    this.props.navigation.navigate('ProductList', { token: store.getState().auth.token });
                }
            }
        })
        .catch(error => {
        });
}


}

function mapStateToProps(state) {
const { error, isLoading } = state.auth

return {
    error,
    isLoading,
}
}

export default connect(mapStateToProps)(LoginComponent)

还要确保将LoginComponent导入其他位置作为默认导入

答案 1 :(得分:1)

对我而言似乎是由于babel设置或其他原因导致的混乱模块导入。您可以在浏览器抱怨的行上设置断点,并在控制台中评估_LoginActions.loginAction。确保它未定义。

在范围内找到_LoginActions,问题就很明显了。如果没有,请告诉我们相应的范围是什么样的。 Scope是chrome dev工具调试程序源代码部分

中的标签