Redux-Observable:Connect(Login)中的mapDispatchToProps()必须返回一个普通对象。而是收到未定义

时间:2019-06-16 15:48:05

标签: redux react-redux redux-observable

我正在根据之前的工作构建一个小型应用程序。动作,史诗和减速器的设置与上一个应用程序完全相同(在该应用程序中一切正常)。但是现在我得到了这个错误:

  Connect(登录)中的

mapDispatchToProps()必须返回一个普通对象。而是收到未定义的消息。

好像我的动作或史诗有问题。但是我尝试的所有方法都不能解决问题。 ReduxDevTools看起来像这样: redux_dev_tools

App.tsx

import React from 'react';
import './App.css';
import { combineReducers, createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import { reducer as formReducer } from 'redux-form';
import { createEpicMiddleware } from 'redux-observable';
import epicReducer from './reducers/root';
import { rootEpic } from './epics';
import Header from './components/Header';
import Login from './components/Login';

const epicMiddleware = createEpicMiddleware();
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const rootReducer = combineReducers({
    epicReducer,
    form: formReducer
});

const store = createStore(
    rootReducer,
    composeEnhancers(applyMiddleware(epicMiddleware))
);

epicMiddleware.run(rootEpic);

const App: React.FC = (props) => {
  return (
        <Provider store={store}>
            <div className="App">
                <Header />
                <Login {...props} />
            </div>
        </Provider>
  );
}

export default App;

Login.tsx

import React, { useState } from 'react';
import styled from 'styled-components';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { userLogin } from '../actions';

const Wrapper = styled.div`
    // some styles
`;

const Card = styled.div`
  // some styles
`;

const Headline = styled.h3`
  // some styles
`;

const Input = styled.input`
  // some styles
`;

const ErrorWrapper = styled.p`
  // some styles
`;

const Button = styled.button`
  // some styles
`;

const Login: React.FC = (props: any) => {

  console.log('login props', props);

  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [serverError, toggleError] = useState(false);
  const [errors, setErrors] = useState({
    email: '',
    password: '',
    serverError: ''
  });

  const validateMail = () => {/* some validation */};

  const validatePassword = () => {/* some validation */};

  return (
    <Wrapper>
      <Card>
        <Headline>Log In</Headline>
        <Input
          placeholder="E-Mail"
          onChange={(e) => setEmail(e.currentTarget.value)}
          onBlur={() => validateMail()}
        />
        {errors.email && <ErrorWrapper>{errors.email}</ErrorWrapper>}
        <Input
          placeholder="Password"
          onChange={(e) => setPassword(e.currentTarget.value)}
          onBlur={() => validatePassword()}
        />
        {errors.password && <ErrorWrapper>{errors.password}</ErrorWrapper>}
        {serverError && <ErrorWrapper>{errors.serverError}</ErrorWrapper>}
        <Button onClick={() => userLogin(email, password)}>
          Login
        </Button>
      </Card>
    </Wrapper>
  )
};

const mapStateToProps = (state: any) => ({ ...state });

const mapDispatchToProps = (dispatch: any) => {
  bindActionCreators({
    userLogin
  }, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(Login);

Actions / index.ts

export const USER_LOGIN = 'USER_LOGIN';
export const USER_LOGIN_SUCCESS = 'USER_LOGIN_SUCCESS';
export const USER_LOGIN_FAILURE = 'USER_LOGIN_FAILURE';

export const userLogin = (email: string, password: string) => ({
    type: USER_LOGIN,
    payload: {email, password}
});

export const userLoginSuccess = (user: Object) => ({
    type: USER_LOGIN_SUCCESS,
    payload: user
});

export const userLoginFailure = (message: string) => ({
    type: USER_LOGIN_FAILURE,
    payload: message
});

epics / index.ts

import "rxjs/add/operator/switchMap";
import "rxjs/add/operator/map";
import "rxjs/add/operator/catch";
import { combineEpics } from "redux-observable";
import axios from 'axios';
import {
    USER_LOGIN,
    userLoginSuccess,
    userLoginFailure
} from '../actions';

function loginEpic(action$: any) {
    return action$
        .ofType(USER_LOGIN)
        .switchMap((payload: any) => {
            return axios.post('url', {
                email: payload.email,
                password: payload.password
            })
            .then((response) => {
                console.log(response)
                return userLoginSuccess(response);
            })
            .catch((error) => {
                console.log(error);
                return userLoginFailure(error);
            })
        })
};

export const rootEpic = combineEpics(
    loginEpic
);

reducers / root.ts

import { USER_LOGIN, USER_LOGIN_SUCCESS, USER_LOGIN_FAILURE } from '../actions';

const initialState = {
    users: [{}],
  isLoading: false,
    error: false,
    errorMessage: ''
};

export default function epicReducer(state = initialState, action: any) {
    switch (action.type) {
        case USER_LOGIN: 
            return {
                ...state,
                isLoading: true
            }
        case USER_LOGIN_SUCCESS:
            return {
                users: [...action.payload],
                isLoading: false,
                error: false,
                errorMessage: ''
            }
        case USER_LOGIN_FAILURE:
            return {
                ...state,
                error: true,
                errorMessage: action.payload
            }
        default:
            return state
    }
}

0 个答案:

没有答案