React组件componentDidMount中fetch首次跳转返回空,刷新才正常如何解决?
问题场景
使用React开发预约详情组件对接Express后端时,出现以下异常:通过hashHistory.push("/appointment/" + this.state.id)跳转到详情组件后,首次拉取接口返回空JSON,console.log(json)输出空对象;但刷新页面或直接访问详情页URL时,可以正常拿到数据。
相关代码
Success.js 组件拉取数据逻辑
async componentDidMount() { try { const response = await fetch(`api/appointments/${this.props.params.id}`) if (!response.ok) { throw Error(response.statusText); } const json = await response.json() // 首次加载组件时这里输出空对象 this.setState({ appointmentDetails: json }) } catch(error) { console.log(error) } }
路由配置
const Routes = (props) => ( <Router {...props}> <Route path="/" component={App} /> <Route path="/appointment" component={BookAppointment} /> <Route path="/appointment/:id" component={Success} /> <Route path="*" component={NotFound} /> </Router> );
后端接口逻辑
router.get('/appointments/:param', (req, res) => { const identification = new ObjectId(req.params.param) Appointment.find({_id: identification}, (err, appointment) => { if (err) console.log(err) else { res.json(appointment) } }) })
根因定位
跳转前未正确等待预约数据异步入库完成,就执行了路由跳转,导致Success组件componentDidMount触发拉取请求时,对应ID的数据还没写入数据库,因此返回空结果。刷新页面时数据已经完成写入,所以可以正常拉取。
修复方案
- 优先调整提交预约的异步逻辑:等待后端返回预约创建成功、写入数据库的响应后,再执行路由跳转,不要提前用本地生成的ID跳转。示例修改如下:
// 预约提交逻辑调整示例 async handleSubmit () { // 提交预约创建请求 const submitRes = await fetch('/api/appointments', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(bookInfo) }) const { appointmentId } = await submitRes.json() // 拿到后端返回的入库后的ID再跳转 hashHistory.push(`/appointment/${appointmentId}`) }
- 增加兜底重试逻辑:如果存在数据库写入延迟、主从同步延迟等场景,可以在详情页的拉取逻辑中增加重试机制,空结果时间隔一定时间重试,最多重试3次即可:
// 调整后的Success componentDidMount async componentDidMount(retryTimes = 0) { try { const response = await fetch(`api/appointments/${this.props.params.id}`) if (!response.ok) throw Error(response.statusText); const json = await response.json() // 结果为空且重试次数未到上限则重试 if (Object.keys(json).length === 0 && retryTimes < 3) { setTimeout(() => this.componentDidMount(retryTimes + 1), 300) return } this.setState({ appointmentDetails: json }) } catch(err) { console.error(err) } }
- 后端接口兼容优化:查询无结果时返回404状态码而非200+空对象,方便前端明确区分请求状态,做对应提示或重试处理。
内容的提问来源于stack exchange,提问作者dementedtiger
相关产品推荐
相关产品推荐

