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

父组件Audit更新state后,子组件CommonDataTable的useEffect未触发

React组件问题:Audit组件更新state后CommonDataTable的useEffect未触发

我有两个独立组件Audit和Reports,二者均渲染CommonDataTable子组件。CommonDataTable中依赖props.data的useEffect钩子在Reports组件中可正常执行,但在Audit组件中,即便父组件将自身state作为props传入,该钩子也不会触发。

Audit组件

function Audit(props: any) {

  const [tableData, setTableData] = React.useState([]);
  const [totalRecords, setTotalRecords] = React.useState(0);
  
  //fetch data and set to state
  const { refetch } = useQuery(GET_AUDIT_DATA, {
    variables: { inputAuditData: { perPage: perPage, page: currentPage,  filterText: "", sortBy: "", sortOrder: "" } },
    onCompleted: (data: any) => {
      console.log("refetch compmleted")
      setTableData(data.records) 
      setTotalRecords(data.totalCount)
    }
  });

  // refetch for data dictionary on data table parameter change
  const refreshData = async ( perPage: number, currentPage: number, filterText:"", sortBy: string, sortOrder: string) => {
      await refetch({
        inputAuditData: { perPage: perPage, page: currentPage, filterText: filterText, sortBy: sortBy, sortOrder: sortOrder }
      })
  }

  return (
    <>
      {console.log("Audit tableData", tableData)}
      <CommonDataTable 
        data={tableData} 
        totalNoRows={totalRecords} 
        refreshData={refreshData} 
      />
      </>
  )
}

Reports组件

function Reports(props: any) {
  const [tableData, setTableData] = React.useState([]);
  const [totalRecords, setTotalRecords] = React.useState(0);

  // fetch report data and set the redux store
  const { refetch } = useQuery(GET_REPORTS_DATA, {
    variables: { inputDataDictionary: { modelID: parseInt(modelId), variables: "", perPage: perPage, page: currentPage, filterText: "", sortBy: "", sortOrder: "" }},
    onCompleted: (data: any) => {
      console.log("refetch compmleted")
      props.initModelData(data) //set data to redux store
      setTotalRecords(data.totalCount) 
    }
  });

  // refetch for reports data on data table parameter change
  const refreshData = async (perPage: number, currentPage: number, filterText: string, sortBy: string, sortOrder: string ) => {
    sortBy = sortBy === 'localizedType' ? 'type' : sortBy
    await refetch({
      inputDataDictionary: { modelID: parseInt(modelId), variables: "", perPage: perPage, page: currentPage, filterText: "", sortBy: sortBy, sortOrder: sortOrder }
      })
  }

  // react hook watches change in redux store and sets state using setTableData()
  React.useEffect(() => {
    setTableData(props.modelData)
  }, [props.modelData]);
  
  return (
    <>
      {console.log("Reports tableData", tableData)}
      <CommonDataTable 
        data={tableData} 
        totalNoRows={totalRecords} 
        refreshData={refreshData} 
        />
   </>    
  )
}

CommonDataTable组件

export default function CommonDataTable(props: any) {
  const [tableData, setTableData] = React.useState([]);

  // should execute to update table data when the data is being refreshed
  React.useEffect(() => {
    console.log("CD setTableData in useEffect ******* ")
    setTableData(props.data)
  }, [props.data]);

  return (
      {console.log("CD tableData", tableData)}
      <DataTable
        data={tableData}
      />
  )
}

如你所见,Audit组件获取数据后直接通过setTableData存入本地state;而Reports组件获取数据后先存入Redux store,再通过监听props.modelData的useEffect将数据存入本地state。两个组件均将tableData作为props传入CommonDataTable组件。

请问为何父组件Audit中setTableData更新state后,子组件CommonDataTable的useEffect钩子未执行?


问题原因及解决方案

1. 数组引用未变化,React浅比较未检测到更新

Audit组件中tableData初始值是[],如果data.records也是空数组(比如首次查询无数据),setTableData(data.records)设置的是同一个引用的数组。React对state的更新检测是浅比较,引用相同会认为state没有变化,父组件不会重新渲染,子组件的props.data也不会更新,因此useEffect不会触发。

解决方法:设置state时创建新的数组引用,比如:

setTableData([...data.records])

2. useQuery缓存导致数据未更新

如果useQuery的缓存中已有相同变量的查询结果,onCompleted可能不会触发,或者返回的data.records和之前的state引用一致。可以调整useQuery的配置,比如:

const { refetch } = useQuery(GET_AUDIT_DATA, {
  variables: { ... },
  onCompleted: (data) => { ... },
  cacheTime: 0, // 禁用缓存
  refetchOnMount: true // 组件挂载时重新查询
})

3. CommonDataTable冗余本地state导致同步问题

CommonDataTable内部维护的tableData本地state是冗余的,完全可以直接使用props.data,避免useEffect的执行时机问题。简化后的组件代码:

export default function CommonDataTable(props: any) {
  return (
    <>
      {console.log("CD tableData", props.data)}
      <DataTable data={props.data} />
    </>
  )
}

这样父组件state更新后,子组件会直接渲染最新数据,无需依赖内部的useEffect。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:20:44