ReactJS如何通过POST请求更新API布尔字段is_archived并解决400报错
错误原因排查
1. 按钮点击事件绑定错误
Activity组件中的归档按钮onClick直接执行了archiveCall函数,而非传入点击时触发的函数引用,导致组件渲染时就自动批量发起请求,请求参数异常触发400。
原代码:
onClick={archiveCall(props.call.id)}
2. fetch配置错误
archiveCall方法中添加了mode: 'no-cors'配置,该配置会强制请求为不透明跨域模式,禁止携带自定义请求头、也无法传输JSON格式的请求体,后端无法解析请求参数返回400。
3. 归档后未同步前端状态
请求完成后没有更新App组件中的calls状态,就算归档成功对应通话记录也不会从页面移除。
4. 全量归档逻辑仅修改本地状态
现有handleArchive方法只是清空了本地state的calls数组,没有调用后端接口批量更新is_archived字段,刷新页面后数据会重置。
修复方案
第一步:修改App.jsx,添加单条归档方法并透传props
import React, { Component} from 'react'; import { ActivityFeed } from './components/activity-feed/activity-feed.component.jsx'; import Header from './Header.jsx'; class App extends Component { constructor() { super(); this.state = { calls: [], showMessage: false, is_archived: false }; } componentDidMount() { fetch('https://aircall-job.herokuapp.com/activities') .then(response => response.json()) .then(activities => this.setState({ calls: activities })) document.getElementById("reset").disabled = true; } // 新增单条通话归档方法 archiveSingleCall = (id) => { fetch(`https://aircall-job.herokuapp.com/activities/${id}`, { method: "POST", headers: { 'Accept' : 'application/json', "Content-Type": "application/json" }, body: JSON.stringify({ is_archived: true }), }).then(res => res.json()) .then(() => { // 归档成功后过滤掉对应id的通话记录 this.setState(prev => ({ calls: prev.calls.filter(call => call.id !== id) })) }) } handleArchive = event => { // 全量归档批量调用接口 Promise.all(this.state.calls.map(call => fetch(`https://aircall-job.herokuapp.com/activities/${call.id}`, { method: "POST", headers: { 'Accept' : 'application/json', "Content-Type": "application/json" }, body: JSON.stringify({is_archived: true}) }) )).then(() => { this.setState({calls: [], showMessage: true }); document.getElementById("archive").disabled = true; document.getElementById("reset").disabled = false; }) }; handleReset = event => { this.componentDidMount(); this.setState({ showMessage: false }); document.getElementById("reset").disabled = true; document.getElementById("archive").disabled = false; }; render() { const { calls, showMessage } = this.state; return ( <div className='App'> <Header/> {/* 把单条归档方法传给子组件 */} <ActivityFeed calls={calls} archiveSingleCall={this.archiveSingleCall} /> <button type="button" className="archive-btn" id="archive" onClick={this.handleArchive}>Archive All Calls</button> {showMessage && <p>All calls have been archived</p>} <button type="button" className="reset-btn" id="reset" onClick={this.handleReset}>Reset Archived Calls</button> </div> ); }; } export default App;
第二步:修改ActivityFeed.component.jsx,透传归档方法
import React from 'react'; import { Activity } from '../activity-detail/activity-detail.component'; import './activity-feed.styles.css'; export const ActivityFeed = props => ( <div className='activity-feed'> {props.calls.map(call => ( <Activity key={call.id} call={call} archiveSingleCall={props.archiveSingleCall}/> ))} </div> );
第三步:修改Activity.component.jsx,修正点击事件、移除冗余逻辑
import React from 'react'; import './activity-detail.styles.css'; import missed from '../../resources/images/missed.svg'; import answered from '../../resources/images/answered.svg'; import voicemail from '../../resources/images/voicemail.svg'; function formatDate(date) { var localDate = new Date(date); return localDate.toDateString().split(' ').slice(1).join(' '); } function formatTime(time) { var localTime = new Date(time); return localTime.toLocaleTimeString().replace(/(.*)\D\d+/, '$1'); } function callType(type) { if (type === "missed") { return <img src={missed} alt="missed" className="call-icon"/> } else if (type === "answered") { return <img src= {answered} alt="answered" className="call-icon"/> } else return <img src= {voicemail} alt="voicemail" className="call-icon"/> } export const Activity = props => ( <div className='activity-container'> <p> Date {formatDate(props.call.created_at)} </p> <p> Time {formatTime(props.call.created_at)} </p> <p> From {props.call.from} </p> <p> To {props.call.to} </p> <p> Via {props.call.via} </p> <p> Call type {callType(props.call.call_type)} </p> {/* 修正点击事件为箭头函数,点击时才触发归档 */} <button type="button" className="archive-call" id="archive-call" onClick={() => props.archiveSingleCall(props.call.id)} >Archive call</button> </div> );
内容的提问来源于stack exchange,提问作者Demoiselle
相关产品推荐
相关产品推荐

