You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React警告:渲染DataTable时无法更新AssignTeacherForAttendance组件

求助:解决React警告“Cannot update a component (AssignTeacherForAttendance) while rendering a different component (DataTable)”

我遇到了React警告:Cannot update a component ('AssignTeacherForAttendance') while rendering a different component ('DataTable')。

警告截图:
警告截图

以下是我的代码:

import { getAuthToken } from '../../utils/auth';
import { API } from '../../config/api/api.config';
import axios from 'axios';
import { resHandlerNoSuccess, responseHandler } from '../../utils/responseHandler';
import { CCard, CCardBody, CCardTitle, CFormInput, CFormLabel } from '@coreui/react';
import { Button } from 'primereact/button';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Calendar } from 'primereact/calendar';
import { Dropdown } from 'primereact/dropdown';

import {
  Form,
  redirect,
  useActionData,
  useLoaderData,
  useNavigation,
  useSearchParams,
  useSubmit,
} from 'react-router-dom';
import { getStandardDropdownLoader } from '../standard/AddSection';
import React, { useCallback, useEffect, useState } from 'react';
import { getSectionDropdownLoader } from '../student/AddStudent';
import { classNames } from 'primereact/utils';

const SectionAccessTable = React.memo(({ sectionAccess, onAccessTypeSort }) => {
  return (
    <DataTable
      value={sectionAccess ? sectionAccess?.section_access : []}
      tableStyle={{ marginLeft: '4px', marginTop: '4px', borderTop: '1px solid  #cccccc' }}
      size="small"
      removableSort
      paginator
      rows={50}
      emptyMessage="No section access found"
    >
      <Column
        header="#"
        body={(data, options) => options.rowIndex + 1}
        style={{ width: '5%' }}
      ></Column>
      <Column field="standard" header="Standard"></Column>
      <Column field="section_name" header="Section"></Column>
      <Column field="faculty_name" header="Faculty"></Column>
      <Column field="user_type" header="User Type"></Column>
      <Column field="from" header="From" sortable></Column>
      <Column field="to" header="to" sortable></Column>
      <Column
        field="access_type"
        header="Access Type"
        sortable
        sortFunction={onAccessTypeSort}
      ></Column>
      <Column header="Action"></Column>
    </DataTable>
  );
});

const AssignTeacherForAttendance = () => {
  // 获取hooks数据
  const { standards, section, faculty, sectionAccess } = useLoaderData();
  const actionData = useActionData();
  let [searchParams, setSearchParams] = useSearchParams();
  let submit = useSubmit();
  // 初始化状态
  const [perPage, setPerPage] = useState(50);
  const [pageNumber, setPageNumber] = useState(1);
  const [sortField, setSortField] = useState('');
  const [sortOrder, setSortOrder] = useState('ASC');

  // 表单数据状态
  const [standardSelected, setStandardSelected] = useState(null);
  const [sectionSelected, setSectionSelected] = useState(null);
  const [facultySelected, setFacultySelected] = useState(null);
  const [accessTypeSelected, setAccessTypeSelected] = useState(null);
  const [fromDate, setFromDate] = useState(null);
  const [toDate, setToDate] = useState(null);
  // 访问类型选项
  const accessType = [
    { access_type: 'same_day' },
    { access_type: 'all_day' },
    { access_type: 'range_day' },
  ];
  // 操作成功后重置表单
  useEffect(() => {
    if (actionData?.success === true) {
      setStandardSelected(null);
      setSectionSelected(null);
      setFacultySelected(null);
      setAccessTypeSelected(null);
      setFromDate(null);
      setToDate(null);
    }
  }, [actionData]);
  // 选择标准后更新搜索参数
  useEffect(() => {
    if (!standardSelected) return;
    setSearchParams({ standard_id: standardSelected });
  }, [standardSelected]);
  // 提交表单
  const onAssignFaculty = useCallback(() => {
    submit(
      {
        section_id: sectionSelected,
        faculty_id: facultySelected,
        access_type: accessTypeSelected,
        from: fromDate,
        to: toDate,
      },
      { method: 'post', encType: 'application/json' },
    );
  }, [sectionSelected, facultySelected, accessTypeSelected, fromDate, toDate, submit]);
  // 访问类型排序逻辑
  const onAccessTypeSort = useCallback(({ data, field, order }) => {
    console.log('>> sorting called');
    const orderNow = order === 1 ? 'ASC' : order === -1 ? 'DESC' : '';
    setSortField(field);
    setSortOrder(orderNow);
  }, []);
  return (
    <>
      <div>
        <form className="flex justify-content-start p-1 flex-wrap">
          <div className="pr-1">
            <Dropdown
              value={standardSelected}
              onChange={(e) => setStandardSelected(e.value)}
              options={standards ? standards : []}
              placeholder="Select standard"
              className={`w-full md:w-11rem p-inputtext-sm`}
              optionValue="id"
              optionLabel="standard"
            />
          </div>
          <div className="pr-1">
            <Dropdown
              value={sectionSelected}
              onChange={(e) => setSectionSelected(e.value)}
              options={section ? section : []}
              placeholder="Select section"
              className="md:w-11rem p-inputtext-sm"
              optionValue="id"
              optionLabel="section_name"
            />
          </div>
          <div className="pr-1">
            <Dropdown
              value={facultySelected}
              onChange={(e) => setFacultySelected(e.value)}
              options={faculty ? faculty : []}
              placeholder="Select Faculty"
              optionLabel="full_name"
              className="md:w-11rem p-inputtext-sm"
              optionValue="id"
            />
          </div>
          <div className="pr-1">
            <Dropdown
              value={accessTypeSelected}
              onChange={(e) => setAccessTypeSelected(e.value)}
              options={accessType ? accessType : []}
              placeholder="Access Type"
              className="md:w-10rem p-inputtext-sm"
              optionValue="access_type"
              optionLabel="access_type"
            />
          </div>
          <div className="pr-1">
            <Calendar
              value={fromDate}
              onChange={(e) => setFromDate(e.value)}
              className="md:w-6rem p-inputtext-sm "
              placeholder="From"
              // touchUI
            />
          </div>
          <div className="pr-1">
            <Calendar
              value={toDate}
              onChange={(e) => setToDate(e.value)}
              className="md:w-6rem p-inputtext-sm "
              placeholder="To"
              // touchUI
            />
          </div>
          <Button
            label="Assign"
            severity="success"
            type="button"
            // disabled={isSubmitting}
            raised
            // loading={isSubmitting}
            size="small"
            onClick={onAssignFaculty}
          />
        </form>
        <SectionAccessTable sectionAccess={sectionAccess} onAccessTypeSort={onAccessTypeSort} />
      </div>
    </>
  );
};
export default AssignTeacherForAttendance;

async function getFacultyDropdownLoader() {
  const token = getAuthToken();
  const facultyDropdownResponse = await axios({
    url: API.endpoint + '/user/faculty-dropdown',
    headers: {
      'Content-Type': 'application/json',
      Authorization: token,
    },
    validateStatus: () => true,
  });
  return resHandlerNoSuccess(facultyDropdownResponse);
}

async function getSectionAccessList({
  sort_field,
  sort_order,
  per_page,
  page_number,
  search_term,
}) {
  const token = getAuthToken();
  const response = await axios({
    url: API.endpoint + '/section-access/list-all',
    params: {
      per_page: per_page ? per_page : 50,
      sort_order: sort_order ? sort_order : 'ASC',
      sort_field: sort_field ? sort_field : '',
      page_number: page_number ? page_number : 1,
    },
    headers: {
      'Content-Type': 'application/json',
      Authorization: token,
    },
    validateStatus: () => true,
  });
  return resHandlerNoSuccess(response);
}

export async function loader({ request }) {
  const url = new URL(request.url);
  const standardId = url.searchParams.get('standard_id');
  const per_page = url.searchParams.get('per_page');
  const sort_order = url.searchParams.get('sort_order');
  const sort_field = url.searchParams.get('sort_field');
  const page_number = url.searchParams.get('page_number');
  const facultyDropdown = await getFacultyDropdownLoader();
  const standardList = await getStandardDropdownLoader();
  const sectionAccessList = await getSectionAccessList({
    per_page,
    sort_order,
    sort_field,
    page_number,
  });
  if (facultyDropdown.redirect) return redirect(facultyDropdown.redirect);
  if (standardList.redirect) return redirect(standardList.redirect);
  if (sectionAccessList.redirect) return redirect(sectionAccessList.redirect);
  if (standardId) {
    const sectionDropdownGot = await getSectionDropdownLoader(standardId);
    if (sectionDropdownGot.redirect) return redirect(sectionDropdownGot.redirect);
    return {
      section: sectionDropdownGot.data,
      standards: standardList.data,
      faculty: facultyDropdown.data?.faculty,
      sectionAccess: sectionAccessList.data,
    };
  }
  return {
    standards: standardList.data,
    faculty: facultyDropdown.data?.faculty,
    sectionAccess: sectionAccessList.data,
  };
}

export async function action({ request, params }) {
  const token = getAuthToken();
  const data = await request.json();
  const responseGot = await axios.post(
    API.endpoint + '/section-access/assign-for-attendance',
    {
      ...data,
    },
    {
      headers: {
        'Content-Type': 'application/json',
        Authorization: token,
      },
      validateStatus: () => true,
    },
  );
  if (!responseGot) return null;
  const responseHandled = responseHandler(responseGot);
  if (responseHandled.redirect) return redirect(responseHandled.redirect);
  return responseHandled.data;
}

我已查阅GitHub相关issue及多个StackOverflow问题,但仍未找到解决方案。

已尝试的优化操作:

  • 在过滤函数中添加回调
  • 将DataTable迁移到独立组件
  • 使用React.memo优化SectionAccessTable的渲染

恳请帮助解决该问题。


内容的提问来源于stack exchange,提问作者Divya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 08:28:11