React调用Django API获取两日期区间数据并在表格展示
React 前端日期范围筛选订单实现方案
现存问题梳理
- 已完成全量订单拉取、日期选择器绑定,但未实现提交后的筛选逻辑
componentDidMount中存在重复赋值orders的冗余代码,会覆盖接口返回的正确订单数据- 日期选择器同时传入
selected和value属性会产生组件冲突 - 未处理日期筛选的边界问题,容易漏掉起止日期当天的订单
- 存在两个绑定同一提交事件的表单,交互逻辑冗余
- 接口拉取用户数据时未给
id字段赋值,头部用户ID展示为空
具体实现步骤
- 调整state结构,新增
filteredOrders字段专门存储当前要展示的订单数据,默认初始为空,拉取完全量数据后和全量订单保持一致 - 删除
componentDidMount里冗余的.then赋值逻辑,在fetchFarmerData拿到全量订单后,同时给orders和filteredOrders赋值,补全id字段的赋值 - 完善
handleSubmit逻辑,用已引入的moment做日期比对:把选中的开始日期转为当天0点,结束日期转为当天23:59:59,遍历全量订单,筛选出added_on在这个时间区间内的订单,赋值给filteredOrders - 调整表格渲染逻辑,遍历数据源从
this.state.orders改为this.state.filteredOrders - 修复日期选择器属性冲突,删掉多余的
value属性,合并重复的表单结构,把生成报告按钮放到日期筛选的同一个表单里 - 可选优化:增加重置按钮,点击后恢复展示全量数据
关键修改代码
state 调整
state = { errorRes: false, errorMessage: "", btnMessage: 0, sendData: false, orders: [], // 存储全量原始订单 filteredOrders: [], // 存储当前要展示的订单(筛选后/全量) startDate: moment().startOf('day').toDate(), // 默认开始日期为当天0点 endDate: moment().endOf('day').toDate(), // 默认结束日期为当天23:59 dataLoaded: false, formSubmitted: false, name: "", id: "", phone: "" // 补全原state缺失的phone字段,避免赋值警告 };
生命周期与数据拉取逻辑修改
// 删除componentDidMount中冗余的then回调 componentDidMount() { this.fetchFarmerData(); } async fetchFarmerData() { var apihandler = new APIHandler(); var farmerdata = await apihandler.fetchFarmerDetails(this.props.match.params.id); const { orders, name, phone, id } = farmerdata.data.data; this.setState({ orders, filteredOrders: orders, // 默认展示全量数据 name, phone, id, // 补全用户ID赋值 dataLoaded: true }); }
筛选提交逻辑实现
handleSubmit = (event) => { event.preventDefault(); const { startDate, endDate, orders } = this.state; // 处理日期边界,避免漏选起止日期当天的数据 const start = moment(startDate).startOf('day'); const end = moment(endDate).endOf('day'); // 前端过滤全量数据 const filtered = orders.filter(order => { const orderTime = moment(order.added_on); return orderTime.isBetween(start, end, null, '[]'); // []参数表示包含起止时间边界 }); this.setState({ filteredOrders: filtered, formSubmitted: true }); } // 可选:重置筛选方法 handleReset = () => { this.setState({ startDate: moment().startOf('day').toDate(), endDate: moment().endOf('day').toDate(), filteredOrders: this.state.orders, formSubmitted: false }) }
表单与表格渲染修改
合并重复表单,修复日期选择器属性问题:
<div className="dt-buttons"> <a className="dt-button buttons-csv buttons-html5" tabIndex="0" aria-controls="DataTables_Table_1" href="#"> <span> <ReactHTMLTableToExcel className="btn btn-success" tabIndex="0" aria-controls="DataTables_Table_1" table="DataTables_Table_1" filename="FarmerStatement" sheet="Sheet" buttonText="Excel" /> </span> </a> <a className="dt-button buttons-print" tabIndex="0" aria-controls="DataTables_Table_1" href="#" onClick={() => this.print()}> <span>Print</span> </a> <br/> </div> <div id="DataTables_Table_1_filter" className="dataTables_filter"> <form onSubmit={this.handleSubmit}> <label> <i className="material-icons">date_range</i>Start Date: <DatePicker selected={this.state.startDate} className="form-control datepicker" name="startDate" aria-controls="DataTables_Table_1" onChange={this.handleStartDateChange} dateFormat="dd/MM/yyyy" /> </label> <br/> <label> <i className="material-icons">date_range</i>End Date: <DatePicker selected={this.state.endDate} className="form-control datepicker" name="endDate" aria-controls="DataTables_Table_1" onChange={this.handleEndDateChange} dateFormat="dd/MM/yyyy" /> </label> <button type="submit" className="btn btn-info" style={{marginLeft: '10px'}}> Generate Report </button> <button type="button" className="btn btn-default" style={{marginLeft: '5px'}} onClick={this.handleReset}> Reset </button> </form> </div>
修改表格遍历数据源,增加空状态提示:
<tbody> {this.state.filteredOrders.length === 0 && this.state.formSubmitted ? ( <tr> <td colSpan="5" className="text-center">所选日期范围内无订单数据</td> </tr> ) : this.state.filteredOrders.map((farmer) => ( <tr role="row" className="odd" key={farmer.id}> <td className="sorting_1">{farmer.id}</td> <td className="sorting_1">{farmer.customer.name}</td> <td className="sorting_1">{farmer.kgs}</td> <td className="sorting_1">{farmer.price}</td> <td className="sorting_1">{new Date(farmer.added_on).toLocaleString()}</td> </tr> ))} </tbody>
注意事项
- 上述前端筛选方案适合单页数据量千条以内的场景,如果总订单量过万,建议把起止日期作为参数传给后端,在接口层做筛选,性能更好
- 用moment的
isBetween方法搭配边界参数可以直接覆盖全天时间,不用手动转时间戳,能避免时区导致的筛选偏差 react-datepicker组件只需要传selected属性绑定值即可,重复传value会导致选值后视图不更新或者控制台报错
内容的提问来源于stack exchange,提问作者Ahmed Sereta
相关产品推荐
相关产品推荐

