在 React 中异步函数完成执行后调用函数
Call a function after an asynchronous function finishes executing in React
我是 React 的新手,正在尝试通过制作小型、简单的应用程序来学习。我正在制作一个简单的 React
应用程序,它具有 Login
功能。我也在使用 Redux store
和 Redux-saga
。我的登录流程是:
- 有一个
Login
组件从用户那里获取 email
和 password
,并在单击登录按钮时进行 POST
调用。
email
和 password
被发送到服务器,如果它们有效,服务器 returns 我保存在 local storage
中的响应中的令牌。
- 如果收到令牌,则会触发
Login success
的操作。在这里,我设置了一个名为 success: true
. 的标志
- 在我的前端,我检查
success
标志的值,如果 success==true
则我重定向到另一个名为 Customers
的页面
登录组件
import React, { Component } from 'react';
import { connect } from "react-redux";
import { withRouter } from 'react-router-dom';
import { loginRequest } from "../../actions/loginActions";
import './styles.css';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
error: '',
};
}
dismissError = () => {
this.setState({ error: '' });
}
handleSubmit = (evt) => {
evt.preventDefault();
let { email, password } = this.state;
if (!email) {
return this.setState({ error: 'Username is required' });
}
if (!password) {
return this.setState({ error: 'Password is required' });
}
let data = {
email: email,
password: password
}
this.props.login(data); //dispatches a method which then makes the POST call
//the checking happens before the above function has finished executing
if (this.props.success)
this.props.history.push('/customers');
else
return this.setState({
error: 'Invalid Username/Password'
});
}
handleChange = (evt) => {
this.setState({
[evt.target.name]: evt.target.value
});
}
render() {
let { email, password } = this.state;
return (
<form className="loginForm" onSubmit={this.handleSubmit}
action="/upload">
<h2>Login</h2>
{
this.state.error &&
<h3 className='error' onClick={this.dismissError}>
<button onClick={this.dismissError}>✖</button>
{this.state.error}
</h3>
}
<label className="FormFields label">Email</label>
<input type="email" className="FormFields" name="email"
value={email}
onChange={(event) => this.handleChange(event)} />
<br />
<label className="FormFields label">Password</label>
<input type="password" className="FormFields" name="password"
value={password}
onChange={(event) => this.handleChange(event)} />
<br />
<input type="submit" className="FormFields submit"
value="Login" />
</form>
);
}
}
const mapStateToProps = (state) => {
return {
loading: state.login.loading,
success: state.login.success
}
}
const mapDispatchToProps = (dispatch) => {
return { login: (data) => {dispatch(loginRequest(data))} }
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Login));
登录 Saga
import { put, takeEvery, call } from 'redux-saga/effects'
import { LOGIN_REQUEST, LOGIN_PENDING, LOGIN_SUCCESS, LOGIN_FAILURE } from '../actions/loginActions';
export function* login(action) {
const { data } = action.payload;
yield put({ type: LOGIN_PENDING })
let url = 'myserverurl/login'
try {
const response = yield call(fetch, url, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
}
});
let tokenObj = yield response.json();
if (response.status === 200) {
localStorage.setItem('user', tokenObj.token);
yield put({ type: LOGIN_SUCCESS, token: tokenObj.token })
}
}
catch (error) {
yield put({ type: LOGIN_FAILURE, error })
}
}
export function* watchLogin() {
yield takeEvery(LOGIN_REQUEST, login)
}
登录减速器非常简单。
登录减速器
import { LOGIN_REQUEST, LOGIN_PENDING, LOGIN_SUCCESS, LOGIN_FAILURE } from '../actions/loginActions';
const initState = {
loading: false,
success: false,
error: ''
}
const loginReducer = (state = initState, action) => {
switch (action.type) {
case LOGIN_REQUEST:
return {
...state,
loading: false
}
case LOGIN_PENDING:
return {
...state,
loading: true
}
case LOGIN_SUCCESS:
return {
...state,
success: true,
loading: false
}
case LOGIN_FAILURE:
return {
...state,
loading: false,
success: false,
error: action.error
}
default: return state;
}
}
export default loginReducer;
登录组件 中的语句 this.props.login(data)
分派操作,然后进行 POST
调用。我想等待上面提到的整个流程完成,然后再检查成功标志的值,但这并没有发生。
在登录的情况下,如何在我的前端检查 success
标志之前等到我的登录减速器的操作完成?我阅读了 async/await
上的文档,但我并不真正理解如何正确使用它们。谁能帮我解决这个问题
您无法在进行异步调用时立即检查 this.props.success
,您需要在 getDerivedStateFromProps
中添加对 success
道具的检查
在您的登录组件中添加 getDerivedStateFromProps
static getDerivedStateFromProps(nextProps, prevState) {
if(!nextProps.loading){
if(nextProps.success === true) {
nextProps.history.push('/customers');
} else {
return { error: 'Invalid Username/Password' }
}
}
return null
}
从 handleSubmit 中删除以下代码
if (this.props.success)
this.props.history.push('/customers');
else
return this.setState({
error: 'Invalid Username/Password'
});
我是 React 的新手,正在尝试通过制作小型、简单的应用程序来学习。我正在制作一个简单的 React
应用程序,它具有 Login
功能。我也在使用 Redux store
和 Redux-saga
。我的登录流程是:
- 有一个
Login
组件从用户那里获取email
和password
,并在单击登录按钮时进行POST
调用。 email
和password
被发送到服务器,如果它们有效,服务器 returns 我保存在local storage
中的响应中的令牌。- 如果收到令牌,则会触发
Login success
的操作。在这里,我设置了一个名为success: true
. 的标志
- 在我的前端,我检查
success
标志的值,如果success==true
则我重定向到另一个名为Customers
的页面
登录组件
import React, { Component } from 'react';
import { connect } from "react-redux";
import { withRouter } from 'react-router-dom';
import { loginRequest } from "../../actions/loginActions";
import './styles.css';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
error: '',
};
}
dismissError = () => {
this.setState({ error: '' });
}
handleSubmit = (evt) => {
evt.preventDefault();
let { email, password } = this.state;
if (!email) {
return this.setState({ error: 'Username is required' });
}
if (!password) {
return this.setState({ error: 'Password is required' });
}
let data = {
email: email,
password: password
}
this.props.login(data); //dispatches a method which then makes the POST call
//the checking happens before the above function has finished executing
if (this.props.success)
this.props.history.push('/customers');
else
return this.setState({
error: 'Invalid Username/Password'
});
}
handleChange = (evt) => {
this.setState({
[evt.target.name]: evt.target.value
});
}
render() {
let { email, password } = this.state;
return (
<form className="loginForm" onSubmit={this.handleSubmit}
action="/upload">
<h2>Login</h2>
{
this.state.error &&
<h3 className='error' onClick={this.dismissError}>
<button onClick={this.dismissError}>✖</button>
{this.state.error}
</h3>
}
<label className="FormFields label">Email</label>
<input type="email" className="FormFields" name="email"
value={email}
onChange={(event) => this.handleChange(event)} />
<br />
<label className="FormFields label">Password</label>
<input type="password" className="FormFields" name="password"
value={password}
onChange={(event) => this.handleChange(event)} />
<br />
<input type="submit" className="FormFields submit"
value="Login" />
</form>
);
}
}
const mapStateToProps = (state) => {
return {
loading: state.login.loading,
success: state.login.success
}
}
const mapDispatchToProps = (dispatch) => {
return { login: (data) => {dispatch(loginRequest(data))} }
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Login));
登录 Saga
import { put, takeEvery, call } from 'redux-saga/effects'
import { LOGIN_REQUEST, LOGIN_PENDING, LOGIN_SUCCESS, LOGIN_FAILURE } from '../actions/loginActions';
export function* login(action) {
const { data } = action.payload;
yield put({ type: LOGIN_PENDING })
let url = 'myserverurl/login'
try {
const response = yield call(fetch, url, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
}
});
let tokenObj = yield response.json();
if (response.status === 200) {
localStorage.setItem('user', tokenObj.token);
yield put({ type: LOGIN_SUCCESS, token: tokenObj.token })
}
}
catch (error) {
yield put({ type: LOGIN_FAILURE, error })
}
}
export function* watchLogin() {
yield takeEvery(LOGIN_REQUEST, login)
}
登录减速器非常简单。
登录减速器
import { LOGIN_REQUEST, LOGIN_PENDING, LOGIN_SUCCESS, LOGIN_FAILURE } from '../actions/loginActions';
const initState = {
loading: false,
success: false,
error: ''
}
const loginReducer = (state = initState, action) => {
switch (action.type) {
case LOGIN_REQUEST:
return {
...state,
loading: false
}
case LOGIN_PENDING:
return {
...state,
loading: true
}
case LOGIN_SUCCESS:
return {
...state,
success: true,
loading: false
}
case LOGIN_FAILURE:
return {
...state,
loading: false,
success: false,
error: action.error
}
default: return state;
}
}
export default loginReducer;
登录组件 中的语句 this.props.login(data)
分派操作,然后进行 POST
调用。我想等待上面提到的整个流程完成,然后再检查成功标志的值,但这并没有发生。
在登录的情况下,如何在我的前端检查 success
标志之前等到我的登录减速器的操作完成?我阅读了 async/await
上的文档,但我并不真正理解如何正确使用它们。谁能帮我解决这个问题
您无法在进行异步调用时立即检查 this.props.success
,您需要在 getDerivedStateFromProps
success
道具的检查
在您的登录组件中添加 getDerivedStateFromProps
static getDerivedStateFromProps(nextProps, prevState) {
if(!nextProps.loading){
if(nextProps.success === true) {
nextProps.history.push('/customers');
} else {
return { error: 'Invalid Username/Password' }
}
}
return null
}
从 handleSubmit 中删除以下代码
if (this.props.success)
this.props.history.push('/customers');
else
return this.setState({
error: 'Invalid Username/Password'
});