我遇到的问题似乎是由于异步调用造成的。我有一个动作,可以进行API调用并推送到“仪表板”页面。该API调用还会根据它返回的响应来更新state.account.id
:
const submitLogin = e => {
e.preventDefault();
props.loginAndGetAccount(credentials);
props.history.push('/protected');
e.target.reset();
}
loginAndGetAccount
来自此操作:
export const loginAndGetAccount = credentials => dispatch => {
dispatch({ type: GET_ACCOUNT_START })
axios
.post('https://foodtrucktrackr.herokuapp.com/api/auth/login/operators', credentials)
.then(res => {
console.log(res);
dispatch({ type: GET_ACCOUNT_SUCCESS, payload: res.data.id })
localStorage.setItem("token", res.data.token)
})
.catch(err => console.log(err));
}
在“仪表板”页面上,我设置了useEffect,以根据state.account.id
中保存的值动态进行另一个API调用。但是,似乎第一个API调用在响应返回并更新state.account.id
之前已推送到“仪表板”页面。因此,在那里进行第二次API调用时,会将state.account.id
作为未定义传递给该动态API调用,这当然会导致失败的调用。我该如何解决?这是正在发生的事情:
const Dashboard = props => {
const [accountInfo, setAccountInfo] = useState({});
useEffect(() => {
console.log(props.accountId);
axiosWithAuth()
.get(`/operator/${props.accountId}`)
.then(res => {
console.log(res);
})
.catch(err => console.log(err));
}, [])
return (
<div>
<h1>This is the Dashboard component</h1>
</div>
)
}
const mapStateToProps = state => {
return {
accountId: state.account.id
}
}
export default connect(mapStateToProps, {})(Dashboard);
问题的根源是您在这里发出请求,但不是
export const loginAndGetAccount = credentials => dispatch => {
dispatch({ type: GET_ACCOUNT_START })
axios
.post('https://foodtrucktrackr.herokuapp.com/api/auth/login/operators', credentials)
.then(res => {
console.log(res);
dispatch({ type: GET_ACCOUNT_SUCCESS, payload: res.data.id })
localStorage.setItem("token", res.data.token)
})
.catch(err => console.log(err));
}
在导航至下一页之前,等待此处完成
const submitLogin = e => {
e.preventDefault();
props.loginAndGetAccount(credentials);
props.history.push('/protected');
e.target.reset();
}
解决此问题的最快方法是先从loginAndGetAccount
返回承诺,然后在该承诺的解决方案中返回props.history.push
...
像这样:
export const loginAndGetAccount = credentials => dispatch => {
dispatch({ type: GET_ACCOUNT_START })
// return the promise here
return axios
.post('https://foodtrucktrackr.herokuapp.com/api/auth/login/operators', credentials)
.then(res => {
console.log(res);
dispatch({ type: GET_ACCOUNT_SUCCESS, payload: res.data.id })
localStorage.setItem("token", res.data.token)
})
.catch(err => console.log(err));
}
...
const submitLogin = e => {
e.preventDefault();
props.loginAndGetAccount(credentials).then(() => {
// so that you can push to history when it resolves (the request completes)
props.history.push('/protected');
e.target.reset();
}
}