Я создаю небольшое приложение на основе моей предыдущей работы. Настройка действий, эпопей и редукторов точно такая же, как и в предыдущем приложении (где все работало просто отлично). Но теперь я получаю эту ошибку:
mapDispatchToProps () в Connect (Login) должен возвращать простой объект. Вместо этого получил неопределенное.
Похоже, что есть какие-то проблемы с моими действиями или эпопеями. Но все, что я пробовал, не решает проблему. 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);
Действия / 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
});
эпос / 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
);
редукторы / 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
}
}