我会尝试给出一个前提,然后再跟上代码。
我决定在我的React项目中实现Material UI,并且大部分工作都在进行中。如何设置应用程序,用户将面临“登录”页面。 Login.js模块呈现SignIn.js module,输入其凭据,然后单击提交。 formData
,onChange
和onSubmit
作为道具从登录组件传递到SignIn组件-并且Login组件通过mapStateToProps
接收它们。 Login组件使用connect中间件将redux状态链接到react应用。
单击提交会触发formData(在Login组件中,传递到SignIn组件中)击中位于login
的{{1}}方法。错误是从此方法内部发生的,在try catch的axios调用处,我尝试与后端"../../actions/auth";
奇怪的是const response = await axios.post("/api/auth", body, config);
从未被击中,这应该将状态设置为从后端返回的令牌,因为似乎从未执行过dispatch({ type: LOGIN_SUCCESS, payload: response.data });
。但是非常奇怪的是,控制台记录令牌的实际工作原理!似乎它从未存储过,从而强制调用AUTH_ERROR。
这是我的登录组件:
LOGIN_SUCCESS
它正在呈现的SignIn组件在这里:
// Login.js
import SignIn from "../../material/SignIn";
const Login = ({ setAlert, login, isAuthenticated }) => {
const [formData, setFormData] = useState({
email: "",
password: ""
});
const { email, password } = formData;
const onChange = e => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const onSubmit = e => {
login(email, password);
};
// Redirect if logged in
if (isAuthenticated) {
return <Redirect to="/dashboard" />;
}
return (
<Fragment>
<SignIn
email={email}
password={password}
onSubmit={onSubmit}
onChange={onChange}
isAuthenticated={isAuthenticated}
/>
</Fragment>
);
};
Login.propTypes = {
setAlert: PropTypes.func.isRequired,
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
};
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
});
export default connect(
mapStateToProps,
{ setAlert, login }
)(Login);
单击“提交”按钮将在我的“登录”组件中引发 // SignIn.js
export default function SignIn({ email, password, onChange, onSubmit }) {
const classes = useStyles();
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form onSubmit={e => onSubmit(e)} className={classes.form} noValidate>
<TextField
variant="outlined"
margin="normal"
required
onChange={e => onChange(e)}
fullWidth
id="email"
label="Email Address"
name="email"
value={email}
// autoComplete="email"
autoFocus
/>
<TextField
variant="outlined"
margin="normal"
required
onChange={e => onChange(e)}
fullWidth
name="password"
label="Password"
type="password"
value={password}
id="password"
autoComplete="current-password"
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="#" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={5}>
<MadeWithLove />
</Box>
</Container>
);
}
方法:
onSubmit
如果您注意到在axios调用之后, // Login user
export const login = (email, password) => async dispatch => {
// Config needed because we're sending data
const config = {
headers: {
"Content-Type": "application/json"
}
};
const body = JSON.stringify({ email, password });
try {
const response = await axios.post("/api/auth", body, config);
// Skips over this dispatch
dispatch({
type: LOGIN_SUCCESS,
payload: response.data
});
// But hits this dispatch.. and then console logs 'REACHED' as seen below
dispatch(loadUser());
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach(error => {
dispatch(setAlert(error.msg, "danger"));
});
}
dispatch({
type: LOGIN_FAIL
});
}
};
定义为:
loadUser is called
后端路由如下:
// Load user
export const loadUser = () => async dispatch => {
const token = localStorage.token;
console.log('REACHED!'); // reached
if (token) {
setAuthToken(token);
}
try {
const response = await axios.get("/api/auth");
dispatch({
type: USER_LOADED,
payload: response.data
});
} catch (err) {
dispatch({
type: AUTH_ERROR // This is dispatched
});
}
};
我现在很困惑。令牌已被渲染,但似乎React在Node有机会将其发回之前并未“等待”响应。
答案 0 :(得分:0)
不确定如何解释这一点,但是我通过摆脱form标记中的onSubmit触发器并将其放在SignIn.js中来解决了这一问题。我将按钮的类型也更改为键入按钮。可以用了:)