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

React useState未正确更新子组件props导致表格渲染延迟求助

React状态更新后表格未即时渲染的问题修复

问题现象

父组件通过子组件1的选择操作更新trackerSetup状态,再将该状态传递给子组件2渲染表格。但选择新值时表格无反应,直到下一次选择才会显示上一次对应的数据。

问题根源与修复步骤

1. 表格组件的useEffect未监听props变化

TrackerTableComponent里的useEffect依赖数组为空,仅在组件首次挂载时执行一次数据请求。当props.trackerSetup更新时,不会重新触发数据获取,导致表格展示旧数据。

修复代码:

useEffect(() => {
  const loadTrackerData = async () => {
    setLoading(true);
    // 添加可选链避免空值报错
    const fetchedTrackers = await getTrackerObject(
      props.trackerSetup?.trackers || []
    );
    console.log("Displaying the following trackers ", fetchedTrackers);
    setTrackers(fetchedTrackers);
    // 异步请求完成后再关闭loading状态
    setLoading(false);
  };
  loadTrackerData();
}, [props.trackerSetup]); // 监听trackerSetup变化

2. 异步逻辑中loading状态更新时机错误

原代码中setLoading(false)直接写在异步函数调用之后,会在请求还未完成时就将loading设为false,导致表格提前渲染旧状态。必须把setLoading(false)移到await操作完成后。

3. 子组件1的useMemo误用

useMemo的设计目的是缓存计算结果,不应该用来执行setState这类副作用操作。这里应该替换为useEffect:

修复代码:

useEffect(() => {
  const existingSetups = JSON.parse(
    localStorage.getItem("trackerSetup")!
  ) as TrackerSetup[];
  setExistingTrackerSetups(existingSetups);
}, []);

4. 可选链优化(可选)

在访问props.trackerSetup.trackers时添加可选链,避免trackerSetup未初始化时抛出空值错误,提升代码健壮性。

完整代码参考

父组件

const MainComponent = () => {
  const [trackerSetup, setTrackerSetup] = useState<TrackerSetup>();

  return (
    <>
      <Container maxWidth="lg">
        <Grid
          direction="row"
          container
          alignItems="center"
          justifyContent="center"
          spacing={2}
          marginTop={5}
        >
          <Grid item xs={6}>
            <AddTrackerSetupComponent />
          </Grid>
          <Grid item xs={6}>
            <SelectTrackerSetupComponent setTrackerSetup={setTrackerSetup} />
          </Grid>
        </Grid>

        {trackerSetup ? (
          <TrackerTableComponent trackerSetup={trackerSetup} />
        ) : (
          <span>选择一个追踪器配置</span>
        )}
      </Container>
    </>
  );
};

export default MainComponent;

子组件1(选择组件)

interface SelectTrackerSetupComponentProps {
  setTrackerSetup: React.Dispatch<React.SetStateAction<TrackerSetup | undefined>>;
}

const SelectTrackerSetupComponent = (
  props: SelectTrackerSetupComponentProps
) => {
  const [existingTrackerSetups, setExistingTrackerSetups] = 
    useState<TrackerSetup[]>();
  const [
    selectedExistingTrackerSetupIndex,
    setSelectedExistingTrackerSetupIndex,
  ] = useState(0);

  useEffect(() => {
    const existingSetups = JSON.parse(
      localStorage.getItem("trackerSetup")!
    ) as TrackerSetup[];
    setExistingTrackerSetups(existingSetups);
  }, []);

  return (
    <>
      {existingTrackerSetups && existingTrackerSetups.length > 0 ? (
        <FormControl fullWidth>
          <InputLabel id="existingSetups">选择已有配置</InputLabel>
          <Select
            labelId="existingSetups"
            id="existingSetups-select"
            label="已有配置"
            value={selectedExistingTrackerSetupIndex}
            onChange={(e) => {
              const selectedIndex = Number(e.target.value);
              setSelectedExistingTrackerSetupIndex(selectedIndex);
              props.setTrackerSetup(existingTrackerSetups[selectedIndex]);
            }}
          >
            {existingTrackerSetups.map((trackerSetup: TrackerSetup, index) => {
              return (
                <MenuItem key={trackerSetup.name} value={index}>
                  {trackerSetup.name}
                </MenuItem>
              );
            })}
          </Select>
        </FormControl>
      ) : (
        <span>加载中..</span>
      )}
    </>
  );
};

export default SelectTrackerSetupComponent;

子组件2(表格组件)

interface TrackerTableComponentProps {
  trackerSetup: TrackerSetup;
}

const TrackerTableComponent = (props: TrackerTableComponentProps) => {
  const [trackers, setTrackers] = useState<Tracker[]>();
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const loadTrackerData = async () => {
      setLoading(true);
      const fetchedTrackers = await getTrackerObject(
        props.trackerSetup?.trackers || []
      );
      console.log("Displaying the following trackers ", fetchedTrackers);
      setTrackers(fetchedTrackers);
      setLoading(false);
    };
    loadTrackerData();
  }, [props.trackerSetup]);

  return (
    <>
      {!loading ? (
        <TableContainer component={Paper}>
          <Table sx={{ minWidth: 650 }} aria-label="simple table">
            <TableHead>
              <TableRow>
                <TableCell>追踪器ID</TableCell>
                <TableCell>固件版本</TableCell>
                <TableCell>电池电量</TableCell>
                <TableCell>操作</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {trackers &&
                trackers.map((tracker: Tracker) => {
                  console.log("Table: displaying tracker ", tracker);
                  return (
                    <TableRow
                      key={tracker.id}
                      sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
                    >
                      <TableCell component="th" scope="row">
                        {tracker.id}
                      </TableCell>
                      <TableCell>{tracker.fwVersion}</TableCell>
                      <TableCell>{tracker.batteryLevel.toString()} %</TableCell>
                      <TableCell>
                        <Button
                          variant="contained"
                          color="success"
                          size="small"
                        >
                          更新固件
                        </Button>
                      </TableCell>
                    </TableRow>
                  );
                })}
            </TableBody>
          </Table>
        </TableContainer>
      ) : (
        <span>加载中...</span>
      )}
    </>
  );
};

export default TrackerTableComponent;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:45:34