You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React生命周期钩子问题:如何阻止组件重载时重复渲染表格数据?

解决React组件重复渲染表格数据及显示延迟问题

看起来你遇到的核心问题有两个:每次页面重载时表格重复添加数据,以及数据需要执行Discard操作后才会显示。咱们一步步拆解解决:

问题根源分析

  1. 请求放在render方法里:React的render会在组件状态/属性变化时多次触发,每次触发都会重新调用SPHttpClient.get请求数据,导致新数据被重复添加到全局变量productsGlobal,进而出现重复行。
  2. 全局变量管理数据productsGlobal是全局变量,React无法追踪它的变化,所以新数据请求回来后不会自动触发表格重新渲染,只有当Discard操作强制组件重新渲染时才会显示新数据。
  3. 初始空行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

火山引擎 最新活动