你好朋友~我有一个问题~我目前正在做一个叫做Lead Manager的简单项目。 但是现在有一个问题。登录按钮不读取 onSubmit 上的道具。 目前,Chrome 出现以下错误。
错误部分:未捕获的类型错误:_this.props.login is not a function Login.js:74
src/components/accounts/Login.js
import React, { Component } from 'react'
import TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';
import Button from '@material-ui/core/Button';
import { Link, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { login } from '../../actions/auth';
export class Login extends Component {
state = {
username: '',
password: ''
}
static propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
onChangeName = (e) => this.setState({ username: e.target.value });
onChangePW1 = (e) => this.setState({ password: e.target.value });
onSubmit = e => {
e.preventDefault();
console.log(this.props.login) // undefined;
this.props.login(this.state.username, this.state.password); <- error;
}
render() {
if (this.props.isAuthenticated) {
return <Redirect to='/' />;
}
const { username, password } = this.state;
return(
<Typography component="div" variant="body1">
<Box color="success.main">
<div>
<h2>Login</h2>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<TextField
id="standard-multiline-flexible"
label="UserName"
type="text"
required
multiline
inputProps={{ maxLength: 10 }}
style={{
width: '70%',
marginLeft: '15%',
marginRight: '15%',
paddingBottom: 10,
marginTop: 0,
}}
getvalue={username}
onChange={this.onChangeName}
/>
</div>
<div className="form-group">
<TextField
id="standard-multiline-flexible"
label="Password"
type="text"
required
multiline
inputProps={{ maxLength: 20 }}
style={{
width: '70%',
marginLeft: '15%',
marginRight: '15%',
paddingBottom: 10,
marginTop: 0,
}}
getvalue={password}
onChange={this.onChangePW1}
/>
</div>
<Button type='submit' color="primary" style={{marginLeft: '15%'}} >Login</Button>
<p align="center">
Don't hava an account? <Link to="/register">Register</Link>
</p>
</form>
</div>
</Box>
</Typography>
);
}
}
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
});
export default connect(mapStateToProps, { login })(Login);
src/actions/auth.js
import axios from 'axios';
import { returnErrors } from './messages';
import {
USER_LOADED,
USER_LOADING,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL
} from './types';
// CHECK TOKEN & LOAD USER
export const loadUser = () => (dispatch, getState) => {
// User Loading
dispatch({ type: USER_LOADING });
// Get token from state
const token = getState().auth.token;
console.log(token)
// Headers
const config = {
headers: {
'Content-Type': 'application/json'
}
}
// If token, add to headers config
if(token) {
config.headers['Authorization'] = `Token ${token}`;
}
axios.get('/api/auth/user', config)
.then(res => {
dispatch({
type: USER_LOADED,
payload: res.data
})
}).catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: AUTH_ERROR
})
})
}
// LOGIN USER
export const login = (username, password) => dispatch => {
// Headers
const config = {
headers: {
'Content-Type': 'application/json'
}
}
// Request Body
const body = JSON.stringify({ username, password });
console.log(body)
axios.post('/api/auth/login', body, config)
.then(res => {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
})
}).catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: LOGIN_FAIL
})
})
}
src/components/App.js
import React, { Component, Fragment } from "react";
import ReactDom from "react-dom";
import { HashRouter as Router, Route, Switch, Redirect } from "react-router-dom";
import Header from "./layout/Header";
import Dashboard from "./leads/Dashboard";
import Alerts from './layout/Alerts';
import Register from './accounts/Register';
import { Login } from './accounts/Login';
import PrivateRoute from './common/PrivateRoute';
import { Provider as AlertProvider, positions } from 'react-alert';
import AlertMUITemplate from 'react-alert-template-mui';
import { Provider } from "react-redux";
import store from "../store";
import { loadUser, login } from '../actions/auth';
// Alert Options
const alertOptions = {
position: positions.MIDDLE
}
class App extends Component {
componentDidMount(){
store.dispatch(loadUser())
}
render() {
return (
<Provider store={store}>
<AlertProvider template={AlertMUITemplate}{...alertOptions}>
<Router>
<Fragment>
<Header />
<Alerts />
<div className="container">
<Switch>
<PrivateRoute exact path="/" component={Dashboard} />
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
</Switch>
</div>
</Fragment>
</Router>
</AlertProvider>
</Provider>
);
}
}
ReactDom.render(<App />, document.getElementById("app"));
如何解决?...如果您能帮助我,我将不胜感激。
答案 0 :(得分:0)
我认为这条线有问题。
export const login = (username, password) => dispatch => {
如果您使用的是 redux 并且想将一个对象传递给您的 mapDispatchToProps
,只需传递函数对象而不进行调度,因为商店将为您管理调度
试试这个吧
export const login = (username, password) => {
然后你应该返回动作 type
和它的 payload
而不需要 dispatch
来自
export const login = (username, password) => dispatch => {
// Headers
const config = {
headers: {
'Content-Type': 'application/json'
}
}
// Request Body
const body = JSON.stringify({ username, password });
console.log(body)
axios.post('/api/auth/login', body, config)
.then(res => {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
})
}).catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: LOGIN_FAIL
})
})
}
到
export const login = async (username, password) => {
// Headers
const config = {
headers: {
'Content-Type': 'application/json'
}
}
// Request Body
const body = JSON.stringify({ username, password });
console.log(body)
return await axios.post('/api/auth/login', body, config)
.then(res => {
return {
type: LOGIN_SUCCESS,
payload: res.data
}
}).catch(err => {
// i do not understand this part, you can modify accordingly
// dispatch(returnErrors(err.response.data, err.response.status));
return {
type: LOGIN_FAIL
)
})
}
注意我的几个编辑:
dispatch
async
以便await
axios 结果答案 1 :(得分:0)
在 src/components/App.js 中更改以下内容:
gcloud sql databases list --instance=mysqlinstance
到
import { Login } from './accounts/Login';
应用程序仍以您最初导入的方式呈现 import Login from './accounts/Login';
组件,因为您的 Login.js 文件中有 Login
。当您使用命名导入 export class Login
时,它正在导入未连接到 Redux 的此类,因此您将无法访问 { Login }
和 isAuthenticated
道具。您实际上可以在此处删除单词 login
。
要获取连接到 Redux 的类,您需要默认导出,即 export
。