reactjs - 解决 API 调用的竞争条件
问题描述
我遇到了一个似乎是由于异步调用引起的问题。我有一个进行 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 调用是在响应返回和更新之前推送到仪表板页面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();
}
.catch(e => {
// handle the error here with some hot logic
})
}
推荐阅读
- react-native - 实例成员不可访问
- java - JSON 日志中的 message 属性有反斜杠
- javascript - 车把均不显示
- java - mapstruct : 使用 mapstruct 将对象数组转换为对象列表
- memory - 如何从 shell 计算给定(Linux)系统上的内存带宽?
- php - PHP curl-setopt POST 与 GET
- java - 启动服务器时如何从 persistence.xml 更改 url 属性
- javascript - 比较 Google 表格中两个范围内的值并计算大于另一个范围的值
- sql-server - MS SQL 服务器故障转移
- go - 获取文件所有者的另一种方法是从 windows 上的 advapi32