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

React Hooks文章发布/取消发布后视图更新问题求助

问题分析与解决方案

这个问题的核心在于React useState的更新是异步的——当你调用setIndexNumStatus(i)之后,indexNumStatus并不会立刻变成最新值,所以紧接着执行const newArrayList = Object.assign([...rowsData], {[indexNumStatus]: d});时,indexNumStatus还是之前的旧值(初始是0),这就导致第一次点击时替换的是索引0的项,第二次点击时才会用上一次正确的索引,出现视图更新异常。

而且你完全不需要额外维护indexNumStatus这个状态,直接在API回调里处理数组更新即可,推荐两种更可靠的方式:


方案1:使用函数式更新+数组map(最简洁)

利用setRowsData的函数式更新特性(接收当前最新的状态作为参数),直接遍历数组替换目标项,不需要手动找索引:

// ListSections.js
const ListSections = ({ sectionData }) => {
  const [rowsData, setRowsData] = React.useState(sectionData);

  /* ** @@ ** @@ PUBLISHED / UNPUBLISHED ** @@ */
  const renderStatusButton = (status, s_id) => (
    <div onClick={() => handleStatusOnClick(status, s_id)}>
      <Status status={status} />
    </div>
  );

  const handleStatusOnClick = (status, s_id) => {
    const changedStatus = status === STATUS.PUBLISHED ? STATUS.UNPUBLISHED : STATUS.PUBLISHED;
    const data = {
      "section": {
        "status": changedStatus
      }
    };

    api
      .put(URLS.CHANGE_COURSE_SECTION(course_id, s_id), data)
      .then(({ data }) => {
        const updatedSection = data.data;
        // 使用函数式更新,确保拿到最新的rowsData
        setRowsData(prevRows => {
          return prevRows.map(row => 
            row.id === updatedSection.id ? updatedSection : row
          );
        });
      })
      .catch(({ response }) => {
        // 错误处理逻辑
      });
  };

  return (
    <TableContainer component={Paper}>
      <Table className={classes.table} aria-label="simple table">
        <TableHead></TableHead>
        <TableBody>
          {rowsData.map((row, index) => (
            <TableRow key={row.id}> {/* 建议用row.id作为key,比index更可靠 */}
              <TableCell align="left">{row.attributes.title}</TableCell>
              <TableCell align="center">
                {row.attributes.status}<br />
                {renderStatusButton(row.attributes.status, row.id)}
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
};
export default ListSections;

方案2:手动找到索引后替换(适合需要额外处理索引的场景)

如果你确实需要用到索引,也可以在回调里直接从当前的rowsData中找到目标项的索引,然后创建新数组:

// 在API的then回调里替换这段代码:
.then(({ data }) => {
  const updatedSection = data.data;
  const targetIndex = rowsData.findIndex(row => row.id === updatedSection.id);
  if (targetIndex !== -1) {
    const newRowsData = [...rowsData];
    newRowsData[targetIndex] = updatedSection;
    setRowsData(newRowsData);
  }
})

额外优化点

  • 把TableRow的key从index改成row.id,因为当数组项顺序变化时,用索引作为key会导致React复用错误的组件,影响性能和状态正确性。
  • 移除了不必要的indexNumStatus状态,减少状态维护的复杂度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 19:12:32