React生命周期钩子问题:如何阻止组件重载时重复渲染表格数据?
解决React组件重复渲染表格数据及显示延迟问题
看起来你遇到的核心问题有两个:每次页面重载时表格重复添加数据,以及数据需要执行Discard操作后才会显示。咱们一步步拆解解决:
问题根源分析
- 请求放在render方法里:React的
render会在组件状态/属性变化时多次触发,每次触发都会重新调用SPHttpClient.get请求数据,导致新数据被重复添加到全局变量productsGlobal,进而出现重复行。 - 全局变量管理数据:
productsGlobal是全局变量,React无法追踪它的变化,所以新数据请求回来后不会自动触发表格重新渲染,只有当Discard操作强制组件重新渲染时才会显示新数据。 - 初始空行:
productsGlobal初始值是[{ id: '', title: '', location: ''}],这会导致表格一开始就显示一行空数据。
解决方案步骤
1. 将数据请求移到componentDidMount生命周期
componentDidMount是组件挂载完成后只会执行一次的钩子,把数据请求放在这里,确保只加载一次数据,彻底避免重复请求。
2. 用组件state管理表格数据
移除全局变量productsGlobal,改用组件的state存储表格数据。这样数据更新时React会自动触发组件重新渲染,表格就能实时显示新数据。
3. 初始化空数组避免空行
把state的初始值设为[],而不是带空对象的数组,初始状态下表格就不会显示空行。
修改后的完整组件代码
import * as React from 'react'; import styles from './AZ.module.scss'; import { IAZProps } from './IAZProps'; import { escape } from '@microsoft/sp-lodash-subset'; import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http'; import { IListItem } from './IListItem'; import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table'; import PanelB from './CompNoteBoard' export interface ISPLists { value: ISPList[]; } export interface ISPList { Id: string; Title: string; Office_x0020_Type: string; Path: string; } export interface INpmsharepoint2State { tableData: Array<{id: string; title: string; location: string}>; } export default class AZ extends React.Component<IAZProps, INpmsharepoint2State> { constructor(props) { super(props); // 初始化state为空数组,避免初始空行 this.state = { tableData: [] }; } // 组件挂载后执行数据请求,仅触发一次 componentDidMount() { this.fetchListItems(); } private fetchListItems = () => { this.props.spHttpClient.get( `${this.props.siteUrl}/sites/dev-sm/_api/web/lists/GetByTitle('CourseBookingTest')/items`, SPHttpClient.configurations.v1, { headers: { 'Accept': 'application/json;odata=nometadata', 'odata-version': '' } } ) .then((response: SPHttpClientResponse): Promise<{ value: IListItem[] }> => { return response.json(); }) .then((response: { value: IListItem[] }) => { console.log(`Successfully loaded ${response.value.length} items`); // 转换数据格式并更新state,触发视图刷新 const formattedData = response.value.map(item => ({ id: item.Id, title: item.Title, location: item.Location })); this.setState({ tableData: formattedData }); }) .catch((error: any) => { alert('Loading all items failed with error' + error); }); } public render(): React.ReactElement<IAZProps> { const selectRowProp = { mode: "checkbox", clickToSelect: true, bgColor: "rgb(238, 193, 213)" }; return ( <div className="container"> <div> <h6>Location Search</h6> <input type='text' width='20' id='meta-area' placeholder="Start typing..."/> <input id='meta_search_ids' value='' /> <br /><br /> <div className={styles.vicinfo} ><br /> <strong>You selected the following location:</strong><br /> <form> ID:<span><input id="id" value='' /></span> <br /> Title: <span><input id="label" value='' /></span> <br /> Address:<span><input id="address" value=''/></span> </form> </div> <br /><br /><br /> <p>{escape(this.props.description)}</p> <div> Learn more </div> <input id="btnShowSecondComp" type="submit" value="View Locations Directory"/> <div> {/* 使用state中的数据渲染表格 */} <BootstrapTable data={this.state.tableData} selectRow={selectRowProp} striped hover condensed pagination insertRow deleteRow search > <TableHeaderColumn dataField="id" isKey={true} dataAlign="right" dataSort width="5%">Course ID</TableHeaderColumn> <TableHeaderColumn dataField="title" dataSort width="5%">Title</TableHeaderColumn> <TableHeaderColumn dataField="location" dataAlign="center" width="5%">Location</TableHeaderColumn> </BootstrapTable> </div> </div> Component 3 <PanelB count={10} key={null} onChange="" index={null} id={null} onRemove details="" description={this.props.description} text="" title="" category={this.props.category} image={this.props.image} > Hello World </PanelB> </div> ); } }
关键修改说明
- 移除全局变量:删除了
productsGlobal等全局变量,改用组件statetableData管理数据,React能自动追踪state变化并更新视图。 - 请求移到componentDidMount:确保数据仅在组件挂载时请求一次,不会重复加载导致重复行。
- 直接更新state触发渲染:请求到数据后转换格式并调用
setState,立即触发组件重新渲染,表格实时显示数据,无需依赖Discard操作。 - 初始空数组:state初始值设为
[],避免表格一开始显示空行。
这样修改后,你的表格就不会再出现重复行,数据也会在请求完成后立即显示了。
内容的提问来源于stack exchange,提问作者KidKode




