[英]Axios request not working with React + Redux
我將嘗試給出一個前提,然后再編寫代碼。
我決定將Material UI實施到我的React項目中,並且大部分工作都在進行中。 如何設置應用程序,用戶將面臨“登錄”頁面。 Login.js模塊呈現SignIn.js模塊 ,輸入其憑據,然后單擊提交。 formData
, onChange
和onSubmit
作為道具從Login組件傳遞到SignIn組件-並且Login組件通過mapStateToProps
接收它們。 Login組件使用connect中間件將redux狀態鏈接到react應用。
單擊提交觸發formData(在Login組件中,傳遞到SignIn組件中)擊中位於"../../actions/auth";
login
方法"../../actions/auth";
。 錯誤是從該方法內部發生的,在try catch中的axios調用處,在此我嘗試與后端const response = await axios.post("/api/auth", body, config);
奇怪的是那個dispatch({ type: LOGIN_SUCCESS, payload: response.data });
從不被命中,這應該將狀態設置為從后端返回的令牌,因為似乎從未執行LOGIN_SUCCESS
。 但是非常奇怪的是,控制台記錄令牌的實際工作原理! 似乎它從未存儲過,從而迫使AUTH_ERROR被調用。
這是我的登錄組件:
// 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組件在這里:
// 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
方法:
// 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
});
}
};
如果您注意到在axios調用之后, 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
});
}
};
后端路由如下:
// @route POST api/auth
// @desc Authenticate user and get token
// @access Public
router.post(
"/",
[
check("email", "Please include a valid email").isEmail(),
check("password", "Please is required").exists()
],
async (req, res) => {
const errors = validationResult(req);
// send back any errors
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array()
});
}
const { email, password } = req.body;
try {
// check if user exists, send error if so
let user = await User.findOne({ email });
if (!user) {
return res
.status(400)
.json({ errors: [{ msg: "Invalid credentials" }] });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res
.status(400)
.json({ errors: [{ msg: "Invalid credentials" }] });
}
// return jsonwebtoken so that way they're logged in right
// away, without having to log in after registering
const payload = {
user: {
id: user.id
}
};
jwt.sign(
payload,
config.get("jwtSecret"),
{
expiresIn: process.env.PORT ? 3600 : 36000
},
(err, token) => {
if (err) throw err;
console.log(token); // prints token!
return res.json({ token });
}
);
} catch (err) {
console.log(err);
res.status(500).send("Server error");
}
}
);
我現在很困惑。 令牌正在被渲染,但似乎React在Node有機會將其發送回之前並未“等待”響應。
不知道如何解釋這一點,但我通過擺脫form標記的onSubmit觸發器並將其放在SignIn.js中來解決了。 我將按鈕的類型也更改為鍵入按鈕。 得到它的工作:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.